def print_transaction(wt): tx_dict = { 'network': wt.network.name, 'fee': wt.fee, 'raw': wt.raw_hex(), 'outputs': [{ 'address': o.address, 'value': o.value } for o in wt.outputs], 'inputs': [{ 'prev_hash': to_hexstring(i.prev_hash), 'output_n': struct.unpack('>I', i.output_n)[0], 'address': i.address, 'signatures': [{ 'signature': to_hexstring(s['signature']), 'sig_der': to_hexstring(s['sig_der']), 'pub_key': to_hexstring(s['pub_key']), } for s in i.signatures], 'value': i.value } for i in wt.inputs] } pprint(tx_dict)
def as_dict(self): """ Get representation of current Block as dictionary. :return dict: """ return { 'block_hash': to_hexstring(self.block_hash), 'height': self.height, 'version': self.version_int, 'prev_block': None if not self.prev_block else to_hexstring(self.prev_block), 'merkle_root': to_hexstring(self.merkle_root), 'timestamp': self.time, 'bits': self.bits_int, 'nonce': self.nonce_int, 'target': self.target_hex, 'difficulty': self.difficulty, 'tx_count': self.tx_count, 'transactions': self.transactions, 'confirmations': self.confirmations }
def prefix_search(wif, network=None): """ Extract network, script type and public/private information from WIF prefix. :param wif: WIF string or prefix in bytes or hexadecimal string :type wif: str, bytes :param network: Limit search to specified network :type network: str :return dict: """ key_hex = change_base(wif, 58, 16) if not key_hex: key_hex = to_hexstring(wif) prefix = key_hex[:8].upper() matches = [] for nw in NETWORK_DEFINITIONS: if network is not None and nw != network: continue data = NETWORK_DEFINITIONS[nw] for pf in data['prefixes_wif']: if pf[1] == prefix: matches.append({ 'prefix': prefix, 'is_private': True if pf[0] == 'private' else False, 'prefix_str': pf[2], 'network': nw, 'script_types': pf[3] }) return matches
def network_by_value(field, value): """ Return all networks for field and (prefix) value. Example, get available networks for WIF or address prefix >>> network_by_value('prefix_wif', 'B0') ['litecoin', 'litecoin_legacy'] >>> network_by_value('prefix_address', '6f') ['testnet', 'litecoin_testnet'] This method does not work for HD prefixes, use 'wif_prefix_search' instead >>> network_by_value('prefix_address', '043587CF') [] :param field: Prefix name from networks definitions (networks.json) :type field: str :param value: Value of network prefix :type value: str, bytes :return list: Of network name strings """ nws = [(nv, NETWORK_DEFINITIONS[nv]['priority']) for nv in NETWORK_DEFINITIONS if NETWORK_DEFINITIONS[nv][field] == value] if not nws: try: value = to_hexstring(value).upper() except TypeError: pass nws = [(nv, NETWORK_DEFINITIONS[nv]['priority']) for nv in NETWORK_DEFINITIONS if NETWORK_DEFINITIONS[nv][field] == value] return [nw[0] for nw in sorted(nws, key=lambda x: x[1], reverse=True)]
def getutxos(self, address, after_txid='', limit=MAX_TRANSACTIONS): utxos = [] utxo_list = [] next_link = '' while True: variables = {'limit': REQ_LIMIT, 'next': next_link, 'dir': 'asc'} res = self.compose_request('address', 'unspent', address, variables=variables) next_link = res['paging']['next'] for utxo in res['unspent']: utxo_list.append(utxo['txid']) if utxo['txid'] == after_txid: utxo_list = [] if not next_link or len(utxos) > REQ_LIMIT_TOTAL: break for txid in utxo_list[:limit]: t = self.gettransaction(txid) for utxo in t.outputs: if utxo.address != address: continue utxos.append( { 'address': utxo.address, 'tx_hash': t.hash, 'confirmations': t.confirmations, 'output_n': utxo.output_n, 'input_n': 0, 'block_height': t.block_height, 'fee': t.fee, 'size': t.size, 'value': utxo.value, 'script': to_hexstring(utxo.lock_script), 'date': t.date }) return utxos
def network_by_value(field, value): """ Return all networks for field and (prefix) value. For Example: network_by_value('prefix_wif', 'B0') Returns: ['litecoin'] :param field: Prefix name from networks definitions (networks.json) :type field: str :param value: Value of network prefix :type value: str, bytes :return list: Of network name strings """ nws = [(nv, NETWORK_DEFINITIONS[nv]['priority']) for nv in NETWORK_DEFINITIONS if NETWORK_DEFINITIONS[nv][field] == value] if not nws: try: value = to_hexstring(value).upper() except TypeError: pass nws = [(nv, NETWORK_DEFINITIONS[nv]['priority']) for nv in NETWORK_DEFINITIONS if NETWORK_DEFINITIONS[nv][field] == value] return [nw[0] for nw in sorted(nws, key=lambda x: x[1], reverse=True)]
def gettransaction(self, txid): tx = self.proxy.getrawtransaction(txid, 1) t = Transaction.import_raw(tx['hex'], network=self.network) t.confirmations = tx['confirmations'] if t.confirmations: t.status = 'confirmed' t.verified = True for i in t.inputs: if i.prev_hash == b'\x00' * 32: i.value = t.output_total i.script_type = 'coinbase' continue txi = self.proxy.getrawtransaction(to_hexstring(i.prev_hash), 1) i.value = int( round( float(txi['vout'][i.output_n_int]['value']) / self.network.denominator)) for o in t.outputs: o.spent = None t.block_hash = tx['blockhash'] t.version = struct.pack('>L', tx['version']) t.date = datetime.utcfromtimestamp(tx['blocktime']) t.hash = txid t.update_totals() return t
def network_values_for(field, output_as='default'): """ Return all prefixes mentioned field, i.e.: prefix_wif, prefix_address_p2sh, etc >>> network_values_for('prefix_wif') [b'\x99', b'\x80', b'\xef', b'\xb0', b'\xb0', b'\xef', b'\xcc', b'\xef'] >>> network_values_for('prefix_address_p2sh') [b'\x95', b'\x05', b'\xc4', b'2', b'\x05', b':', b'\x10', b'\x13'] :param field: Prefix name from networks definitions (networks.json) :type field: str :param output_as: Output as string or hexstring. Default is string or hexstring depending on field type. :type output_as: str :return str: """ r = [ _format_value(field, nv[field]) for nv in NETWORK_DEFINITIONS.values() ] if output_as == 'str': return [normalize_var(i) for i in r] elif output_as == 'hex': return [to_hexstring(i) for i in r] else: return r
def _parse_transaction(self, tx, block_height=None, get_input_values=True): t = Transaction.import_raw(tx['hex'], network=self.network) t.confirmations = None if 'confirmations' not in tx else tx[ 'confirmations'] if t.confirmations or block_height: t.status = 'confirmed' t.verified = True for i in t.inputs: if i.prev_hash == b'\x00' * 32: i.script_type = 'coinbase' continue if get_input_values: txi = self.proxy.getrawtransaction(to_hexstring(i.prev_hash), 1) i.value = int( round( float(txi['vout'][i.output_n_int]['value']) / self.network.denominator)) for o in t.outputs: o.spent = None t.block_hash = tx.get('block_hash', tx['txid']) # FIXME, use only one t.block_height = block_height t.version = struct.pack('>L', tx['version']) t.date = datetime.utcfromtimestamp(tx['time']) t.update_totals() return t
def _parse_transaction(self, tx, block_height=None, get_input_values=True): t = Transaction.import_raw(tx['hex'], network=self.network) t.confirmations = None if 'confirmations' not in tx else tx['confirmations'] t.status = 'unconfirmed' for i in t.inputs: if i.prev_hash == b'\x00' * 32: i.script_type = 'coinbase' continue if get_input_values: txi = self.proxy.getrawtransaction(to_hexstring(i.prev_hash), 1) i.value = int(round(float(txi['vout'][i.output_n_int]['value']) / self.network.denominator)) for o in t.outputs: o.spent = None t.block_hash = tx.get('blockhash', '') if not block_height and t.block_hash: block_height = self.proxy.getblock(t.block_hash, 1)['height'] t.block_height = block_height if not t.confirmations and block_height is not None: if not self.latest_block: self.latest_block = self.blockcount() t.confirmations = (self.latest_block - block_height) + 1 if t.confirmations or block_height: t.status = 'confirmed' t.verified = True t.version = struct.pack('>L', tx['version']) t.date = None if 'time' not in tx else datetime.utcfromtimestamp(tx['time']) t.update_totals() return t
def network_by_value(field, value): """ Return all networks for field and (prefix) value. For Example: network_by_value('prefix_wif', 'B0') Returns: ['litecoin'] :param field: Prefix name from networks definitions (networks.json) :type field: str :param value: Value of network prefix :type value: str, bytes :return list: Of network name strings """ try: value = to_hexstring(value).upper() except: pass return [ nv for nv in NETWORK_DEFINITIONS if NETWORK_DEFINITIONS[nv][field] == value ]
def getutxos(self, address, after_txid='', limit=MAX_TRANSACTIONS): # First get all transactions for this address from the blockchain from bitcoinlib.services.services import Service srv = Service(network=self.network.name, providers=['bcoin']) txs = srv.gettransactions(address, limit=25) # Fail if large number of transactions are found if not srv.complete: raise ClientError( "If not all transactions known, we cannot determine utxo's. " "Increase limit or use other provider") utxos = [] for tx in txs: for unspent in tx.outputs: if unspent.address != address: continue if not srv.isspent(tx.txid, unspent.output_n): utxos.append({ 'address': unspent.address, 'tx_hash': tx.txid, 'confirmations': tx.confirmations, 'output_n': unspent.output_n, 'input_n': 0, 'block_height': tx.block_height, 'fee': tx.fee, 'size': tx.size, 'value': unspent.value, 'script': to_hexstring(unspent.lock_script), 'date': tx.date, }) if tx.txid == after_txid: utxos = [] return utxos[:limit]
def wif_prefix_search(wif, witness_type=None, multisig=None, network=None): """ Extract network, script type and public/private information from HDKey WIF or WIF prefix. Example, get bitcoin 'xprv' info: >>> wif_prefix_search('0488ADE4', network='bitcoin', multisig=False) [{'prefix': '0488ADE4', 'is_private': True, 'prefix_str': 'xprv', 'network': 'bitcoin', 'witness_type': 'legacy', 'multisig': False, 'script_type': 'p2pkh'}] Or retreive info with full WIF string: >>> wif_prefix_search('xprv9wTYmMFdV23N21MM6dLNavSQV7Sj7meSPXx6AV5eTdqqGLjycVjb115Ec5LgRAXscPZgy5G4jQ9csyyZLN3PZLxoM1h3BoPuEJzsgeypdKj', network='bitcoin', multisig=False) [{'prefix': '0488ADE4', 'is_private': True, 'prefix_str': 'xprv', 'network': 'bitcoin', 'witness_type': 'legacy', 'multisig': False, 'script_type': 'p2pkh'}] Can return multiple items if no network is specified: >>> [nw['network'] for nw in wif_prefix_search('0488ADE4', multisig=True)] ['bitcoin', 'dash'] :param wif: WIF string or prefix in bytes or hexadecimal string :type wif: str, bytes :param witness_type: Limit search to specific witness type :type witness_type: str :param multisig: Limit search to multisig: false, true or None for both. Default is both :type multisig: bool :param network: Limit search to specified network :type network: str :return dict: """ key_hex = '' if len(wif) > 8: try: key_hex = change_base(wif, 58, 16) except: pass else: key_hex = wif if not key_hex: key_hex = to_hexstring(wif) prefix = key_hex[:8].upper() matches = [] for nw in NETWORK_DEFINITIONS: if network is not None and nw != network: continue data = NETWORK_DEFINITIONS[nw] for pf in data['prefixes_wif']: if pf[0] == prefix and (multisig is None or pf[3] is None or pf[3] == multisig) and \ (witness_type is None or pf[4] is None or pf[4] == witness_type): matches.append({ 'prefix': prefix, 'is_private': True if pf[2] == 'private' else False, 'prefix_str': pf[1], 'network': nw, 'witness_type': pf[4], 'multisig': pf[3], 'script_type': pf[5] }) return matches
def store_transaction(self, t, order_n=None, commit=True): """ Store transaction in cache. Use order number to determine order in a block :param t: Transaction :type t: Transaction :param order_n: Order in block :type order_n: int :param commit: Commit transaction to database. Default is True. Can be disabled if a larger number of transactions are added to cache, so you can commit outside this method. :return: """ if not self.cache_enabled(): return # Only store complete and confirmed transaction in cache if not t.txid: # pragma: no cover _logger.info("Caching failure tx: Missing transaction hash") return False elif not t.date or not t.block_height or not t.network: _logger.info("Caching failure tx: Incomplete transaction missing date, block height or network info") return False elif not t.coinbase and [i for i in t.inputs if not i.value]: _logger.info("Caching failure tx: One the transaction inputs has value 0") return False raw_hex = None if CACHE_STORE_RAW_TRANSACTIONS: raw_hex = t.raw_hex() if not raw_hex: # pragma: no cover _logger.info("Caching failure tx: Raw hex missing in transaction") return False if self.session.query(DbCacheTransaction).filter_by(txid=t.txid).count(): return new_tx = DbCacheTransaction(txid=t.txid, date=t.date, confirmations=t.confirmations, block_height=t.block_height, block_hash=t.block_hash, network_name=t.network.name, fee=t.fee, raw=raw_hex, order_n=order_n) self.session.add(new_tx) for i in t.inputs: if i.value is None or i.address is None or i.output_n is None: # pragma: no cover _logger.info("Caching failure tx: Input value, address or output_n missing") return False new_node = DbCacheTransactionNode(txid=t.txid, address=i.address, output_n=i.index_n, value=i.value, is_input=True) self.session.add(new_node) for o in t.outputs: if o.value is None or o.address is None or o.output_n is None: # pragma: no cover _logger.info("Caching failure tx: Output value, address, spent info or output_n missing") return False new_node = DbCacheTransactionNode( txid=t.txid, address=o.address, output_n=o.output_n, value=o.value, is_input=False, spent=o.spent, spending_txid=None if not o.spending_txid else to_hexstring(o.spending_txid), spending_index_n=o.spending_index_n) self.session.add(new_node) if commit: try: self.commit() _logger.info("Added transaction %s to cache" % t.txid) except Exception as e: # pragma: no cover _logger.warning("Caching failure tx: %s" % e)
def sign(self, msg): """ Sign a message with private key, Return signature """ priv = PrivateKey(self.key.private_byte, raw=True) sig = priv.ecdsa_sign(msg) h = priv.ecdsa_serialize_compact(sig) return self.key.public_hex, encoding.to_hexstring(h)
def sendrawtransaction(self, rawtx): """ Push a raw transaction to the network :param rawtx: Raw transaction as hexstring :type rawtx: str, bytes :return dict: Send transaction result """ rawtx = to_hexstring(rawtx) return self._provider_execute('sendrawtransaction', rawtx)
def getrawtransaction(self, txid): """ Get a raw transaction by its transaction hash :param txid: Transaction identification hash :type txid: str, bytes :return str: Raw transaction as hexstring """ txid = to_hexstring(txid) return self._provider_execute('getrawtransaction', txid)
def gettransaction(self, txid): """ Get a transaction by its transaction hash. Convert to Bitcoinlib transaction object. :param txid: Transaction identification hash :type txid: str, bytes :return Transaction: A single transaction object """ txid = to_hexstring(txid) return self._provider_execute('gettransaction', txid)
def test_blocks_parse_genesis(self): raw_block = '0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3' \ 'e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a29ab5f49ffff001d1dac2b7c010100000001000000000000000000' \ '0000000000000000000000000000000000000000000000ffffffff4d04ffff001d0104455468652054696d657320303' \ '32f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f7574' \ '20666f722062616e6b73ffffffff0100f2052a01000000434104678afdb0fe5548271967f1a67130b7105cd6a828e03' \ '909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac00000000' b = Block.from_raw(to_bytes(raw_block), height=0) self.assertEqual(to_hexstring(b.block_hash), '000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f') self.assertEqual(b.height, 0) self.assertEqual(b.version_int, 1) self.assertEqual(b.prev_block, 32 * b'\x00') self.assertEqual(to_hexstring(b.merkle_root), '4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b') self.assertEqual(to_hexstring(b.bits), '1d00ffff') self.assertEqual(b.time, 1231006505) self.assertEqual(to_hexstring(b.nonce), '7c2bac1d') self.assertEqual(b.difficulty, 1) self.assertEqual(b.target_hex, '00000000ffff0000000000000000000000000000000000000000000000000000') self.assertEqual(b.tx_count, 1) self.assertEqual(str(b), '<Block(000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f, 0, transactions: 1)>')
def sendrawtransaction(self, rawtx): """ Dummy method to send transactions on the bitcoinlib testnet. The bitcoinlib testnet does not exists, so it just returns the transaction hash. :param rawtx: A raw transaction hash :type rawtx: bytes, str :return str: Transaction hash """ txid = to_hexstring( hashlib.sha256(hashlib.sha256( to_bytes(rawtx)).digest()).digest()[::-1]) return {'txid': txid, 'response_dict': {}}
def gettransaction(self, txid): tx = self.proxy.getrawtransaction(txid, 1) t = Transaction.import_raw(tx['hex'], network=self.network) t.confirmations = tx['confirmations'] if t.confirmations: t.status = 'confirmed' t.verified = True for i in t.inputs: txi = self.proxy.getrawtransaction(to_hexstring(i.prev_hash), 1) value = int(float(txi['vout'][i.output_n_int]['value']) / self.network.denominator) i.value = value t.block_hash = tx['blockhash'] t.version = tx['version'] t.date = datetime.fromtimestamp(tx['blocktime']) t.update_totals() return t
def getrawtransaction(self, txid): """ Get a raw transaction by its transaction hash :param txid: Transaction identification hash :type txid: str, bytes :return str: Raw transaction as hexstring """ txid = to_hexstring(txid) self.results_cache_n = 0 rawtx = self.cache.getrawtransaction(txid) if rawtx: self.results_cache_n = 1 return rawtx return self._provider_execute('getrawtransaction', txid)
def test_blocks_parse_block_and_transactions(self): b = Block.from_raw(self.rb250000, parse_transactions=True) self.assertEqual(to_hexstring(b.block_hash), '000000000000003887df1f29024b06fc2200b55f8af8f35453d7be294df2d214') self.assertEqual(b.height, 250000) self.assertEqual(b.version_int, 2) self.assertEqual(b.prev_block, to_bytes('0000000000000009c2e82d884ec07b4aafb64ca3ef83baca2b6b0b5eb72c8f02')) self.assertEqual(b.merkle_root, to_bytes('16ec1eafaca8ca59d182cbf94f29b50b06ac4207b883f380b9bf547fe8fed723')) self.assertEqual(b.bits_int, 0x1972dbf2) self.assertEqual(b.time, 1375533383) self.assertEqual(b.nonce_int, 0x917661) self.assertEqual(int(b.difficulty), 37392766) self.assertEqual(b.target, 720982641204331278205950312227594303241470815982254303477760) self.assertEqual(b.tx_count, 156) self.assertEqual(b.transactions[0].txid, '7ae2ab185a6e501753f6e29e5b6a98ba040098acb7c11ffed9430f22ed5263a3') self.assertEqual(b.transactions[49].txid, '3b6d97f107cba804270f4d22fafda3295b3bfb735366da6c1473157cc94a5f7c') self.assertEqual(b.transactions[122].txid, 'a5cc9bd850b6eedc3e466b3e0f5c85fb640de0a3537259eb0cae761d0a4f78b4') self.assertEqual(b.transactions[155].txid, 'e3d6cb87bd37ca53509cdc9ecdabf82ef966d9b25a2598b7de87c8173beb40d5')
def network_values_for(field, output_as='default'): """ Return all prefixes mentioned field, i.e.: prefix_wif, prefix_address_p2sh, prefix_hdkey_public, etc :param field: Prefix name from networks definitions (networks.json) :type field: str :param output_as: Output as string or hexstring. Default is string or hexstring depending on field type. :type output_as: str :return str: """ r = [_format_value(field, nv[field]) for nv in NETWORK_DEFINITIONS.values()] if output_as == 'str': return [normalize_var(i) for i in r] elif output_as == 'hex': return [to_hexstring(i) for i in r] else: return r
def gettransaction(self, txid): tx = self.compose_request('txs', txid, variables={'includeHex': 'true'}) t = Transaction.import_raw(tx['hex'], network=self.network) # t.hash = to_bytes(txid) # t.txid = txid if tx['confirmations']: t.status = 'confirmed' t.date = datetime.strptime(tx['confirmed'][:19], "%Y-%m-%dT%H:%M:%S") else: t.status = 'unconfirmed' t.confirmations = tx['confirmations'] t.block_height = tx['block_height'] if tx['block_height'] > 0 else None t.block_hash = tx.get('block_hash') t.fee = tx['fees'] t.rawtx = to_bytes(tx['hex']) t.size = int(len(tx['hex']) / 2) t.network = self.network t.input_total = 0 if len(t.inputs) != len(tx['inputs']): raise ClientError( "Invalid number of inputs provided. Raw tx: %d, blockcypher: %d" % (len(t.inputs), len(tx['inputs']))) for n, i in enumerate(t.inputs): if not t.coinbase and not ( tx['inputs'][n]['output_index'] == i.output_n_int and tx['inputs'][n]['prev_hash'] == to_hexstring(i.prev_hash)): raise ClientError( "Transaction inputs do not match raw transaction") if 'output_value' in tx['inputs'][n]: if not t.coinbase: i.value = tx['inputs'][n]['output_value'] t.input_total += i.value if len(t.outputs) != len(tx['outputs']): raise ClientError( "Invalid number of outputs provided. Raw tx: %d, blockcypher: %d" % (len(t.outputs), len(tx['outputs']))) for n, o in enumerate(t.outputs): if 'spent_by' in tx['outputs'][n]: o.spent = True o.spending_txid = tx['outputs'][n]['spent_by'] return t
def gettransactions(self, address, after_txid='', max_txs=MAX_TRANSACTIONS): txs = [] while True: variables = {'limit': LIMIT_TX, 'after': after_txid} retries = 0 while retries < 3: try: res = self.compose_request('tx', 'address', address, variables) except ReadTimeout as e: sleep(3) _logger.info("Bcoin client error: %s" % e) retries += 1 else: break finally: if retries == 3: raise ClientError( "Max retries exceeded with bcoin Client") for tx in res: txs.append(self._parse_transaction(tx)) if len(txs) >= max_txs: break if len(res) == LIMIT_TX: after_txid = res[LIMIT_TX - 1]['hash'] else: break # Check which outputs are spent/unspent for this address if not after_txid: address_inputs = [(to_hexstring(inp.prev_hash), inp.output_n_int) for ti in [t.inputs for t in txs] for inp in ti if inp.address == address] for tx in txs: for to in tx.outputs: if to.address != address: continue spent = True if (tx.hash, to.output_n) in address_inputs else False txs[txs.index(tx)].outputs[to.output_n].spent = spent return txs
def test_blocks_parse_block_and_transactions(self): b = Block.from_raw(self.rb330000, parse_transactions=True, limit=5) self.assertEqual(to_hexstring(b.block_hash), '00000000000000000faabab19f17c0178c754dbed023e6c871dcaf74159c5f02') self.assertEqual(b.height, 330000) self.assertEqual(b.version_int, 2) self.assertEqual(b.prev_block, to_bytes('000000000000000003e20f90920dc065da4a507bcf045f44b9abac7fabff4857')) self.assertEqual(b.merkle_root, to_bytes('5a97519772c615a875c12859f447d9c1fea922f7e36bd08e96cc95eee235d28f')) self.assertEqual(b.bits_int, 404472624) self.assertEqual(b.time, 1415983209) self.assertEqual(b.nonce_int, 3756201140) self.assertEqual(int(b.difficulty), 39603666252) self.assertEqual(b.tx_count, 81) self.assertEqual(b.transactions[0].txid, 'dfd63430f8d14f6545117d74b20da63efd4a75c7e28f723b3dead431b88469ee') self.assertEqual(b.transactions[4].txid, '717bc8b42f12baf771b6719c2e3b2742925fe3912917c716abef03e35fe49020') self.assertEqual(len(b.transactions), 5) b.parse_transactions(70) self.assertEqual(len(b.transactions), 75) b.parse_transactions(10) self.assertEqual(len(b.transactions), 81) self.assertEqual(b.transactions[80].txid, '7c8483c890942334ecb73db3802f7571b06047b5c15febe3bad11e460065709b')
def gettransaction(self, txid): """ Get a transaction by its transaction hash. Convert to Bitcoinlib transaction object. :param txid: Transaction identification hash :type txid: str, bytes :return Transaction: A single transaction object """ txid = to_hexstring(txid) tx = None self.results_cache_n = 0 if self.min_providers <= 1: tx = self.cache.gettransaction(txid) if tx: self.results_cache_n = 1 if not tx: tx = self._provider_execute('gettransaction', txid) if len(self.results) and self.min_providers <= 1: self.cache.store_transaction(tx, 0) return tx
def getutxos(self, address, after_txid='', max_txs=MAX_TRANSACTIONS): txs = self.gettransactions(address, after_txid=after_txid, max_txs=max_txs) utxos = [] for tx in txs: for unspent in tx.outputs: if unspent.address != address: continue if not self.isspent(tx.hash, unspent.output_n): utxos.append({ 'address': unspent.address, 'tx_hash': tx.hash, 'confirmations': tx.confirmations, 'output_n': unspent.output_n, 'input_n': 0, 'block_height': tx.block_height, 'fee': tx.fee, 'size': tx.size, 'value': unspent.value, 'script': to_hexstring(unspent.lock_script), 'date': tx.date, }) return utxos
def get_key_format(key, isprivate=None): """ Determins the type (private or public), format and network key. This method does not validate if a key is valid. :param key: Any private or public key :type key: str, int, bytes, bytearray :param isprivate: Is key private or not? :type isprivate: bool :return dict: Dictionary with format, network and isprivate """ if not key: raise BKeyError("Key empty, please specify a valid key") key_format = "" networks = None if isinstance(key, (bytes, bytearray)) and len(key) in [128, 130]: key = to_hexstring(key) if not (isprivate is None or isinstance(isprivate, bool)): raise BKeyError("Attribute 'is_private' must be False or True") elif isinstance(key, numbers.Number): key_format = 'decimal' isprivate = True elif isinstance(key, (bytes, bytearray)) and len(key) in [ 33, 65 ] and key[:1] in [b'\2', b'\3']: key_format = 'bin_compressed' isprivate = False elif isinstance(key, (bytes, bytearray)) and (len(key) in [33, 65] and key[:1] == b'\4'): key_format = 'bin' isprivate = False elif isinstance( key, (bytes, bytearray)) and len(key) == 33 and key[-1:] == b'\1': key_format = 'bin_compressed' isprivate = True elif isinstance(key, (bytes, bytearray)) and len(key) == 32: key_format = 'bin' isprivate = True elif len(key) == 130 and key[:2] == '04' and not isprivate: key_format = 'public_uncompressed' isprivate = False elif len(key) == 128: key_format = 'hex' if isprivate is None: isprivate = True elif len(key) == 66 and key[:2] in ['02', '03'] and not isprivate: key_format = 'public' isprivate = False elif len(key) == 64: key_format = 'hex' if isprivate is None: isprivate = True elif len(key) == 66 and key[-2:] in ['01'] and not (isprivate is False): key_format = 'hex_compressed' isprivate = True elif len(key) == 58 and key[:2] == '6P': key_format = 'wif_protected' isprivate = True else: try: key_hex = change_base(key, 58, 16) networks = network_by_value('prefix_wif', key_hex[:2]) if networks: if key_hex[-10:-8] == '01': key_format = 'wif_compressed' else: key_format = 'wif' isprivate = True else: networks = network_by_value('prefix_hdkey_private', key_hex[:8]) if networks: key_format = 'hdkey_private' isprivate = True else: networks = network_by_value('prefix_hdkey_public', key_hex[:8]) if networks: key_format = 'hdkey_public' isprivate = False # TODO: Recognise address key and implement in Key en HDKey classs # else: # networks = network_by_value('prefix_address_p2sh', key_hex[:2]) + \ # network_by_value('prefix_address', key_hex[:2]) # if networks: # key_format = 'address' # isprivate = False except (TypeError, EncodingError): pass if not key_format: try: int(key) if 70 < len(key) < 78: key_format = 'decimal' isprivate = True except (TypeError, ValueError): pass if not key_format: raise BKeyError("Key: %s. Unrecognised key format" % key) else: return { "format": key_format, "networks": networks, "isprivate": isprivate }