diff --git a/blockchain_parser/blockchain.py b/blockchain_parser/blockchain.py index 8a29bd1..454e7c2 100644 --- a/blockchain_parser/blockchain.py +++ b/blockchain_parser/blockchain.py @@ -16,6 +16,11 @@ import stat import plyvel +from blockchain_parser.transaction import Transaction +from blockchain_parser.index import DBTransactionIndex +from blockchain_parser import utils +from binascii import unhexlify +from binascii import hexlify from .block import Block from .index import DBBlockIndex from .utils import format_hash @@ -146,7 +151,6 @@ def _index_confirmed(self, chain_indexes, num_confirmations=6): if len(chain) == num_confirmations: return first_block.hash in chain - def get_ordered_blocks(self, index, start=0, end=None, cache=None): """Yields the blocks contained in the .blk files as per the heigt extract from the leveldb index present at path @@ -168,8 +172,8 @@ def get_ordered_blocks(self, index, start=0, end=None, cache=None): with open(cache, 'wb') as f: pickle.dump(blockIndexes, f) - # remove small forks that may have occured while the node was live. - # Occassionally a node will receive two different solutions to a block + # remove small forks that may have occurred while the node was live. + # Occasionally a node will receive two different solutions to a block # at the same time. The Leveldb index saves both, not pruning the # block that leads to a shorter chain once the fork is settled without # "-reindex"ing the bitcoind block data. This leads to at least two @@ -217,3 +221,36 @@ def get_ordered_blocks(self, index, start=0, end=None, cache=None): break blkFile = os.path.join(self.path, "blk%05d.dat" % blkIdx.file) yield Block(get_block(blkFile, blkIdx.data_pos), blkIdx.height) + + def get_transaction(self, txid, db): + """Yields the transaction contained in the .blk files as a python + object, similar to + https://developer.bitcoin.org/reference/rpc/getrawtransaction.html + """ + + byte_arr = bytearray.fromhex(txid) + byte_arr.reverse() + tx_hash = hexlify(b't').decode('utf-8') + \ + hexlify(byte_arr).decode('utf-8') + + tx_hash_fmtd = unhexlify(tx_hash) + raw_hex = db.get(tx_hash_fmtd) + + tx_idx = DBTransactionIndex(utils.format_hash(tx_hash_fmtd), raw_hex) + blk_file = os.path.join(self.path, "blk%05d.dat" % tx_idx.blockfile_no) + raw_hex = get_block(blk_file, tx_idx.file_offset) + + offset = tx_idx.block_offset + + transaction_data = raw_hex[80:] + # Try from 1024 (1KiB) -> 1073741824 (1GiB) slice widths + for j in range(0, 20): + try: + offset_e = offset + (1024 * 2 ** j) + transaction = Transaction.from_hex( + transaction_data[offset:offset_e]) + return transaction + except Exception: + continue + + return None diff --git a/blockchain_parser/index.py b/blockchain_parser/index.py index 8334500..aaaedc0 100644 --- a/blockchain_parser/index.py +++ b/blockchain_parser/index.py @@ -51,7 +51,7 @@ def __init__(self, blk_hash, raw_hex): self.undo_pos, i = _read_varint(raw_hex[pos:]) pos += i - assert(pos + 80 == len(raw_hex)) + assert (pos + 80 == len(raw_hex)) self.version, p, m, time, bits, self.nonce = unpack( "