def card_bundle_parser(bundle: CardBundle, debug=False) -> Iterator: '''this function wraps all the card transfer parsing''' try: # first vout of the bundle must pay to deck.p2th validate_card_transfer_p2th(bundle.deck, bundle.vouts[0]) # second vout must be OP_RETURN with card_metainfo card_metainfo = parse_card_transfer_metainfo( read_tx_opreturn(bundle.vouts[1]), bundle.deck.version ) # if any of this exceptions is raised, return None except (InvalidCardTransferP2TH, CardVersionMismatch, CardNumberOfDecimalsMismatch, RecieverAmountMismatch, DecodeError, TypeError, InvalidNulldataOutput) as e: if debug: print(e) # re-do as logging later on return yield # check for decimals if not card_metainfo["number_of_decimals"] == bundle.deck.number_of_decimals: raise CardNumberOfDecimalsMismatch( {"error": "Number of decimals does not match."} ) # deduce the individual cards in the bundle cards = card_postprocess(card_metainfo, bundle.vouts) # drop the vouts property del bundle.__dict__['vouts'] for c in cards: d = {**c, **bundle.__dict__} try: yield CardTransfer(**d) # issuing cards to issuing address is forbidden, # this will except the error except InvalidCardIssue as e: if debug: print(e)
def test_card_types_invalid(): deck = Deck( name="decky", issuer='muMpqVjUDq5voY9WnxvFb9sFvZm8wwKihu', number_of_decimals=1, issue_mode=IssueMode.MONO.value, network="tppc", production=True, version=1, ) with pytest.raises(InvalidCardIssue): card_transfer = CardTransfer( deck=deck, sender=deck.issuer, receiver=[deck.issuer], amount=[1], version=1, )
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
def test_card_types_transfer(): deck = Deck( name="decky", issuer='muMpqVjUDq5voY9WnxvFb9sFvZm8wwKihu', number_of_decimals=1, issue_mode=IssueMode.MONO.value, network="tppc", production=True, version=1, ) card_transfer = CardTransfer( deck=deck, sender='mxrr8ALSs9fmHEszs5y1w5tRsDv9r7M2bK', receiver=['mxrr8ALSs9fmHEszs5y1w5tRsDv9r7M2bK'], amount=[1], version=1, ) assert card_transfer.type == 'CardTransfer'
def test_card_types_issue(): deck = Deck( name="decky", issuer='muMpqVjUDq5voY9WnxvFb9sFvZm8wwKihu', number_of_decimals=1, issue_mode=IssueMode.MULTI.value, network="tppc", production=True, version=1, ) card_transfer = CardTransfer( deck=deck, sender=deck.issuer, receiver=['mmsiUudS9W5xLoWeA44JmKa28cioFg7Yzx'], amount=[1], version=1, ) assert card_transfer.type == 'CardIssue'
def test_card_transfer_object(): deck = Deck( name="decky", number_of_decimals=2, issue_mode=IssueMode.MULTI.value, network="ppc", production=True, version=1, asset_specific_data="Just testing.", ) card_transfer = CardTransfer( deck=deck, receiver=["PDZ9MPBPPjtT6qdJm98PhLVY9gNtFUoSLT"], amount=[1], version=1, ) assert card_transfer.metainfo_to_protobuf == b'\x08\x01\x12\x01\x01\x18\x02' assert card_transfer.__dict__ == { 'amount': [1], 'network': deck.network, 'asset_specific_data': None, 'blockhash': '', 'blocknum': 0, 'blockseq': 0, 'cardseq': 0, 'confirms': 0, 'deck_id': None, 'number_of_decimals': 2, 'receiver': ['PDZ9MPBPPjtT6qdJm98PhLVY9gNtFUoSLT'], 'sender': None, 'timestamp': 0, 'txid': None, 'type': 'CardTransfer', 'version': 1, 'deck_p2th': None }
def test_oversize_card_object(): deck = Deck( name="decky", number_of_decimals=12, issue_mode=IssueMode.MULTI.value, network="ppc", production=True, version=1, asset_specific_data="Just testing.", ) with pytest.raises(OverSizeOPReturn): card_transfer = CardTransfer( deck=deck, receiver=[Kutil(network='ppc').address for i in range(80)], amount=[random.randint(20, 12000) for i in range(80)], version=1, ) assert card_transfer.metainfo_to_protobuf
def few_random_cards(deck: Deck, n: int, card_type: str = 'random', amount: int = None) -> list: '''returns <n> randomly generated cards''' types = ['CardIssue', 'CardBurn', 'CardTransfer'] cards = [ CardTransfer( deck=deck, receiver=[Kutil(network='tppc').address], amount=[random.randint(1, 100)], ) for i in range(n) ] if card_type == 'transfer': for i in cards: i.__setattr__('type', 'CardTransfer') if card_type == 'random': for i in cards: i.__setattr__('type', random.choice(types)) if card_type == 'issue': for i in cards: i.__setattr__('type', 'CardIssue') if card_type == 'burn': for i in cards: i.__setattr__('type', 'CardBurn') if amount: # if there is strict requirement for amount to be <int> for i in cards: i.amount = [amount] return cards
def test_deck_state(): '''test DeckState calculations''' deck = Deck( name="my_test_deck", number_of_decimals=0, issue_mode=4, # MULTI network="tppc", production=True, version=1, issuer='msnHPXDWuJhRBPVNQnwXdKvEMQHLr9z1P5') receiver_roster = [ 'mzsMJgqVABFhrEGrqKH7qURhmxESx4K8Ti', 'mmsiUudS9W5xLoWeA44JmKa28cioFg7Yzx', 'muMpqVjUDq5voY9WnxvFb9sFvZm8wwKihu', 'mxrr8ALSs9fmHEszs5y1w5tRsDv9r7M2bK' ] amounts = [10, 20, 30, 40] card_issues = [ CardTransfer( deck=deck, receiver=[r], amount=[a], sender=deck.issuer, blockseq=0, blocknum=1, blockhash= 'd9ec32b461d80b6a549a09f5ddd550f6e2fa9021f8efe4fd7413be6c471c0b56', txid= 'fe8f88c2a3a700a664f9547cb9c48466f900553d0a6bdb504ad52340ef00c9a0', cardseq=amounts.index(a)) for r, a in zip(receiver_roster, amounts) ] transfers = [] # list of card transfers # first member of the roster sends it's 10 cards to third member of the roster transfers.append( CardTransfer( deck=deck, sender=receiver_roster[0], receiver=[receiver_roster[2]], amount=[amounts[0]], blockhash= 'c5a03576178843eb5a1f1e6b878678f2c7d47b6f561fe06059e0518645b8e50e', blocknum=2, blockseq=1, cardseq=0, txid= '08c886a43ce9f95a5673bc95374259b0f9eca9de1e5fb9bb7aa7826834820133', type='CardTransfer')) # second member of the roster burns it's 20 cards, he calls it a scam too transfers.append( CardTransfer( deck=deck, sender=receiver_roster[1], receiver=[deck.issuer], # burn amount=[amounts[1]], blockseq=1, blockhash= 'd6cecad875b05e9b34cb05680de0bee4f5d69ba83df23a6b6a14d1090dc992e3', cardseq=0, blocknum=3, txid= 'b27161ba476d29c2255d097aaa4e236752b9891a46d1fdb88f5225ee677b976e', type='CardBurn')) # third member of the roster sends out it's cards to r[0] and r[3] transfers.append( CardTransfer( deck=deck, sender=receiver_roster[2], receiver=[receiver_roster[0]], amount=[10], blockseq=1, blocknum=5, blockhash= 'd638dc2d60623d16cb6b39fc165a6e7514a28c426b02db32058b87fada1cabdb', cardseq=0, txid= 'ebe36158ca3f364910f8a1c0f9b1b2696bed4522f84551bdb42ffd57360ce232', type='CardTransfer')) transfers.append( CardTransfer( deck=deck, sender=receiver_roster[2], receiver=[receiver_roster[3]], amount=[20], blockseq=1, blocknum=5, blockhash= 'd638dc2d60623d16cb6b39fc165a6e7514a28c426b02db32058b87fada1cabdb', txid= 'ebe36158ca3f364910f8a1c0f9b1b2696bed4522f84551bdb42ffd57360ce232', type='CardTransfer', cardseq=1)) # fourth member of the roster is sending 10 of it's cards to second member transfers.append( CardTransfer( deck=deck, sender=receiver_roster[3], receiver=[receiver_roster[1]], amount=[10], blockseq=1, blocknum=200, blockhash= '2896066f76f0c0f609ee0e92d195d0eb48891b91f90fa4c9a51381e9f9510b7a', txid= '764afbfe6b3cecd3be8161fef363a08b8b14e7c631b4b7fbbc8edbc1475ab0fe', type='CardTransfer', cardseq=0)) state = DeckState(card_issues + transfers) assert len(state.cards) == 9 assert len(list(state.processed_burns)) == 1 assert len(list(state.processed_issues)) == 4 assert len(list(state.processed_transfers)) == 4 assert state.checksum assert state.balances[receiver_roster[0]] == 10 assert state.balances[receiver_roster[1]] == 10 assert state.balances[receiver_roster[2]] == 10 assert state.balances[receiver_roster[3]] == 50