def find_deck_spawns(provider: Provider, prod: bool = True) -> Iterable[str]: '''find deck spawn transactions via Provider, it requires that Deck spawn P2TH were imported in local node or that remote API knows about P2TH address.''' pa_params = param_query(provider.network) if isinstance(provider, RpcNode): if prod: decks = (i["txid"] for i in provider.listtransactions("PAPROD")) else: decks = (i["txid"] for i in provider.listtransactions("PATEST")) if isinstance(provider, Mintr): if prod: decks = (i["txid"] for i in provider.listtransactions(pa_params.P2TH_addr)) else: raise NotImplementedError if isinstance(provider, Cryptoid) or isinstance(provider, Explorer): if prod: decks = (i for i in provider.listtransactions(pa_params.P2TH_addr)) else: decks = ( i for i in provider.listtransactions(pa_params.test_P2TH_addr)) return decks
def find_card_bundles(provider: Provider, deck: Deck) -> Optional[Iterator]: '''each blockchain transaction can contain multiple cards, wrapped in bundles. This method finds and returns those bundles.''' if isinstance(provider, RpcNode): if deck.id is None: raise Exception("deck.id required to listtransactions") p2th_account = provider.getaccount(deck.p2th_address) batch_data = [('getrawtransaction', [i["txid"], 1]) for i in provider.listtransactions(p2th_account)] result = provider.batch(batch_data) if result is not None: raw_txns = [i['result'] for i in result if result] else: raise EmptyP2THDirectory({'error': 'No cards found on this deck.'}) else: if deck.p2th_address is None: raise Exception("deck.p2th_address required to listtransactions") try: raw_txns = (provider.getrawtransaction(i, 1) for i in provider.listtransactions(deck.p2th_address)) except TypeError: raise EmptyP2THDirectory({'error': 'No cards found on this deck.'}) return (card_bundler(provider, deck, i) for i in raw_txns)
def find_all_valid_decks(provider: Provider, deck_version: int, prod: bool=True) -> Generator: ''' Scan the blockchain for PeerAssets decks, returns list of deck objects. : provider - provider instance : version - deck protocol version (0, 1, 2, ...) : test True/False - test or production P2TH ''' pa_params = param_query(provider.network) if prod: p2th = pa_params.P2TH_addr else: p2th = pa_params.test_P2TH_addr if isinstance(provider, RpcNode): deck_spawns = (provider.getrawtransaction(i, 1) for i in find_deck_spawns(provider)) else: try: deck_spawns = (provider.getrawtransaction(i, 1) for i in provider.listtransactions(p2th)) except TypeError as err: # it will except if no transactions are found on this P2TH raise EmptyP2THDirectory(err) with concurrent.futures.ThreadPoolExecutor(max_workers=2) as th: for result in th.map(deck_parser, ((provider, rawtx, deck_version, p2th) for rawtx in deck_spawns)): if result: yield result
def find_card_bundles(provider: Provider, deck: Deck) -> Optional[Iterator]: '''each blockchain transaction can contain multiple cards, wrapped in bundles. This method finds and returns those bundles.''' if isinstance(provider, RpcNode): if deck.id is None: raise Exception("deck.id required to listtransactions") batch_data = [('getrawtransaction', [i["txid"], 1]) for i in provider.listtransactions(deck.id)] result = provider.batch(batch_data) if result is not None: raw_txns = [i['result'] for i in result if result] else: raise EmptyP2THDirectory({'error': 'No cards found on this deck.'}) else: if deck.p2th_address is None: raise Exception("deck.p2th_address required to listtransactions") try: raw_txns = (provider.getrawtransaction(i, 1) for i in provider.listtransactions(deck.p2th_address)) except TypeError: raise EmptyP2THDirectory({'error': 'No cards found on this deck.'}) return (CardBundle(deck=deck, blockhash=i['blockhash'], txid=i['txid'], timestamp=i['time'], blockseq=tx_serialization_order(provider, i["blockhash"], i["txid"]), blocknum=provider.getblock(i["blockhash"])["height"], sender=find_tx_sender(provider, i), vouts=i['vout'], tx_confirmations=i['confirmations'] ) for i in raw_txns)
def find_vote_casts(provider: Provider, vote: Vote, choice_index: int) -> Iterable[VoteCast]: '''find and verify vote_casts on this vote_choice_address''' vote_casts = provider.listtransactions( vote.vote_choice_address[choice_index]) for tx in vote_casts: raw_tx = provider.getrawtransaction(tx, 1) sender = find_tx_sender(provider, raw_tx) confirmations = raw_tx["confirmations"] blocknum = provider.getblock(raw_tx["blockhash"])["height"] yield VoteCast(vote, sender, blocknum, confirmations, raw_tx["blocktime"])
def find_vote_inits(provider: Provider, deck: Deck) -> Iterable[Vote]: '''find vote_inits on this deck''' vote_ints = provider.listtransactions(deck_vote_tag(deck)) for txid in vote_ints: try: raw_vote = provider.getrawtransaction(txid) vote = parse_vote_info(read_tx_opreturn(raw_vote)) vote["vote_id"] = txid vote["sender"] = find_tx_sender(provider, raw_vote) vote["deck"] = deck yield Vote(**vote) except AssertionError: pass
def get_card_transfers(provider: Provider, deck: Deck) -> Generator: '''get all <deck> card transfers, if cards match the protocol''' if isinstance(provider, RpcNode): if deck.id is None: raise Exception("deck.id required to listtransactions") batch_data = [('getrawtransaction', [i["txid"], 1]) for i in provider.listtransactions(deck.id)] result = provider.batch(batch_data) if result is not None: card_transfers = [i['result'] for i in result if result] else: if deck.p2th_address is None: raise Exception("deck.p2th_address required to listtransactions") if provider.listtransactions(deck.p2th_address): card_transfers = (provider.getrawtransaction( i, 1) for i in provider.listtransactions(deck.p2th_address)) else: raise EmptyP2THDirectory({'error': 'No cards found on this deck.'}) def card_parser(args: Tuple[Provider, Deck, dict]) -> list: '''this function wraps all the card transfer parsing''' provider = args[0] deck = args[1] raw_tx = args[2] try: validate_card_transfer_p2th(deck, raw_tx) # validate P2TH first card_metainfo = parse_card_transfer_metainfo( read_tx_opreturn(raw_tx), deck.version) vouts = raw_tx["vout"] sender = find_tx_sender(provider, raw_tx) try: # try to get block seq number blockseq = tx_serialization_order(provider, raw_tx["blockhash"], raw_tx["txid"]) except KeyError: blockseq = 0 try: # try to get block number of block when this tx was written blocknum = provider.getblock(raw_tx["blockhash"])["height"] except KeyError: blocknum = 0 try: # try to get tx confirmation count tx_confirmations = raw_tx["confirmations"] except KeyError: tx_confirmations = 0 cards = postprocess_card(card_metainfo, raw_tx, sender, vouts, blockseq, blocknum, tx_confirmations, deck) cards = [CardTransfer(**card) for card in cards] except (InvalidCardTransferP2TH, CardVersionMismatch, CardNumberOfDecimalsMismatch, InvalidVoutOrder, RecieverAmountMismatch, DecodeError, TypeError, InvalidNulldataOutput) as e: return [] return cards with concurrent.futures.ThreadPoolExecutor(max_workers=2) as th: for result in th.map(card_parser, ((provider, deck, i) for i in card_transfers)): if result: yield result