import base64 import struct from typing import List from lbrynet.schema.types.v2.page_pb2 import Page as PageMessage from lbrynet.wallet.transaction import Transaction, Output class Page: __slots__ = 'txs', 'txos', 'offset', 'total' def __init__(self, txs, txos, offset, total): self.txs: List[Transaction] = txs self.txos: List[Output] = txos self.offset = offset self.total = total @classmethod def from_base64(cls, data: str) -> 'Page': return cls.from_bytes(base64.b64decode(data)) @classmethod def from_bytes(cls, data: bytes) -> 'Page': page_message = PageMessage() page_message.ParseFromString(data) tx_map, txo_list = {}, [] for tx_message in page_message.txs: tx = Transaction(tx_message.raw, height=tx_message.height, position=tx_message.position) tx_map[tx.hash] = tx for txo_message in page_message.txos: output = tx_map[txo_message.tx_hash].outputs[txo_message.nout] if txo_message.WhichOneof('meta') == 'claim': claim = txo_message.claim output.meta = { 'is_winning': claim.is_winning, 'effective_amount': claim.effective_amount, 'trending_amount': claim.trending_amount, } if claim.HasField('channel'): output.channel = tx_map[claim.channel.tx_hash].outputs[claim.channel.nout] txo_list.append(output) return cls(list(tx_map.values()), txo_list, page_message.offset, page_message.total) @classmethod def to_base64(cls, tx_rows, txo_rows, offset, total) -> str: return base64.b64encode(cls.to_bytes(tx_rows, txo_rows, offset, total)).decode() @classmethod def to_bytes(cls, tx_rows, txo_rows, offset, total) -> bytes: page = PageMessage() page.total = total page.offset = offset for tx in tx_rows: tx_message = page.txs.add() tx_message.raw = tx['raw'] tx_message.height = tx['height'] tx_message.position = tx['position'] for txo in txo_rows: txo_message = page.txos.add() txo_message.tx_hash = txo['txo_hash'][:32] txo_message.nout, = struct.unpack('<I', txo['txo_hash'][32:]) if 'channel_txo_hash' in txo and txo['channel_txo_hash']: txo_message.claim.channel.tx_hash = txo['channel_txo_hash'][:32] txo_message.claim.channel.nout, = struct.unpack('<I', txo['channel_txo_hash'][32:]) if 'is_winning' in txo: # claim txo_message.claim.is_winning = bool(txo['is_winning']) txo_message.claim.activation_height = txo['activation_height'] txo_message.claim.effective_amount = txo['effective_amount'] txo_message.claim.trending_amount = txo['trending_amount'] return page.SerializeToString()