async def process_pocketable_block_message(self, block_data, amount): raw_block = get_raw_block_from_json(block_data) link_block = LinkBlock( block=raw_block, amount=amount ) try: recipient = link_block.recipient except ValueError: logger.warning( "Received block %s wasn't pocketable", link_block.block_hash ) return if recipient not in self.account_sync_statuses: logger.warning( "Received pocketable block %s didn't belong to any of " "the accounts in the wallet", link_block.block_hash ) return link_block.timestamp = Timestamp( date=int(time.time()), source=TimestampSource.BROADCAST ) self.pocketable_block_queue.put(link_block)
def test_sort_blocks_for_broadcast(wallet_factory): wallet = wallet_factory(balance=10000) account_ids = [ wallet.accounts[0].account_id, wallet.accounts[10].account_id, wallet.accounts[5].account_id, wallet.accounts[8].account_id ] blocks = [] destination = account_ids[1] for _ in range(0, 5): for j in range(0, 4): source = account_ids[j] try: destination = account_ids[j + 1] except IndexError: destination = account_ids[0] send_block = wallet.send(source=source, destination=destination, amount=1000) link_block = LinkBlock(amount=1000, block=send_block.block) receive_block = wallet.account_map[destination].receive_block( link_block) blocks += [send_block, receive_block] block_hashes = [block.block_hash for block in blocks] # Shuffle the blocks and sort them, ensuring the order remains the same random.shuffle(blocks) blocks = sort_blocks_for_broadcast(blocks) assert block_hashes == [block.block_hash for block in blocks]
async def listen_for_msg(self): broadcast_keepalive = (self.keepalive_timestamp + self.KEEPALIVE_INTERVAL_SECONDS < time.time()) if broadcast_keepalive: await self.ws_conn.send_json({"event": "keepalive"}) self.keepalive_timestamp = time.time() try: response = await self.ws_conn.receive_json(timeout=0.1) except asyncio.TimeoutError: return msg = response["data"] block_data = msg["block"] account_id = normalize_account_id(block_data["account"]) amount = int(msg["amount"]) if amount != 0: raw_block = get_raw_block_from_json(block_data) if raw_block.tx_type in ("send", "receive", "send/receive"): link_block = LinkBlock(block=raw_block, amount=amount) if link_block.recipient in self.subscribed_account_ids: await self.process_pocketable_block_message( block_data=block_data, amount=amount) if account_id in self.subscribed_account_ids: subtype = block_data["type"] if block_data["type"] == "state": if "is_send" in msg: subtype = \ "send" if msg["is_send"] == "true" else "receive" await self.process_account_block_message(block_data=block_data, account_id=account_id, subtype=subtype)
def test_link_block_create_block_or_block_data(self): block = RawBlock.from_dict(STATE_LINK_BLOCK_DATA) with pytest.raises(ValueError) as exc: LinkBlock(block=block, block_data=STATE_LINK_BLOCK_DATA, amount=10000) assert "Only 'block_data' or 'block' is accepted" in str(exc.value)
async def process_block_message(self, response): """ Process a block and insert it into the account and/or pocketable queue """ msg = response["message"] account_id = normalize_account_id(msg["account"]) block_data = msg["block"] subtype = msg["block"]["subtype"] if account_id in self.account_sync_statuses: await self.process_account_block_message( block_data=block_data, account_id=account_id, subtype=subtype ) amount = int(msg.get("amount", 0)) if amount != 0: raw_block = get_raw_block_from_json(block_data) if raw_block.tx_type not in ("send", "receive", "send/receive"): return link_block = LinkBlock( block=raw_block, amount=amount ) if link_block.recipient in self.account_sync_statuses: await self.process_pocketable_block_message( block_data=block_data, amount=int(msg["amount"]) )
def test_link_block_verify_invalid_work(self): block_data = STATE_LINK_BLOCK_DATA.copy() block_data["work"] = "0"*16 block = RawBlock.from_dict(block_data, verify=False) with pytest.raises(InvalidWork): LinkBlock(block=block, amount=10000, verify=True)
def test_link_block_verify_invalid_signature(self): block_data = STATE_LINK_BLOCK_DATA.copy() block_data["signature"] = "0"*128 block = RawBlock.from_dict(block_data, verify=False) with pytest.raises(InvalidSignature): LinkBlock(block=block, amount=10000, verify=True)
def get_link_block_from_json(block_data): """ Deserialize block data received from a node's JSON response to a LinkBlock instance. """ raw_block = RawBlock.from_json(block_data["contents"]) local_timestamp = None if "local_timestamp" in block_data and block_data["local_timestamp"]: local_timestamp = int(block_data["local_timestamp"]) link_block = LinkBlock(block=raw_block, amount=int(block_data["amount"])) if local_timestamp: link_block.timestamp = Timestamp(date=local_timestamp, source=TimestampSource.NODE) return link_block
def test_link_block_create_legacy(self): block = RawBlock.from_dict(LEGACY_LINK_BLOCK_DATA) link_block = LinkBlock(block=block, amount=10000) assert link_block.amount == 10000 assert link_block.block_hash == \ "D5721A0E8485C15DB60577C0573ABA961EA51BF496C720A890E31CD910E62B2B" assert link_block.recipient == \ "nano_3u7d5iohy14swyhxhgfm9iq4xa9yibhcgnyj697uwhicp14dhx4woik5e9ek"
def test_link_block_create_state(self): block = RawBlock.from_dict(STATE_LINK_BLOCK_DATA) link_block = LinkBlock(block=block, amount=10000) assert link_block.amount == 10000 assert link_block.block_hash == \ "96970559D7257F63ACB8383ED57CB510745DE744ABCEC4DC41590CE7E32179EA" assert link_block.recipient == \ "xrb_1zoiejrbyey3x6tn5o6eqmmas1szy64x5wzqo9qppf8d6gn6mctm1ndnrgyy"
def test_account_legacy_send_balance(self): """ Test that balance is calculated correctly for legacy send blocks """ account = Account( account_id="xrb_1jeqoxg7cpo5xgyxhcwzsndeuqp6yyr9m63k8tfu9mskjdfo7iq95p1ktb8j", source=AccountSource.WATCHING, representative="xrb_3dmtrrws3pocycmbqwawk6xs7446qxa36fcncush4s1pejk16ksbmakis78m" ) account.add_block( Block( block_data={ "account": "xrb_1jeqoxg7cpo5xgyxhcwzsndeuqp6yyr9m63k8tfu9mskjdfo7iq95p1ktb8j", "type": "open", "representative": "xrb_3dmtrrws3pocycmbqwawk6xs7446qxa36fcncush4s1pejk16ksbmakis78m", "source": "01BB6121002B428124BB0C546B3195F36108D30F8E664DC60777F3B4102A705F", "work": "e847031ddf0c4cef", "signature": "E23FA05FC070E176195A4860EC2E73966AE040A91B6F972B5843B31879BBBD32EF0D0186FF9EC2EF1714274FF45B7FF715FDF99BB3ED4571AD8798A28BAF1B0E", }, link_block=LinkBlock( block_data={ "account": "xrb_1uz6t43ztbffhft3zonpwf4hrjd9gorg53j8ac48ijppo6t4kj1px9jnimwj", "destination": "xrb_1jeqoxg7cpo5xgyxhcwzsndeuqp6yyr9m63k8tfu9mskjdfo7iq95p1ktb8j", "type": "send", "previous": "D04DEDF65FE1A99AA6759285512A6DE6708961443538C80CA588B032017497D6", "work": "547ac17fc277bd4c", "signature": "60C7D5546289179A480477BBEB62CB9BE8ABDD6B52DA4FC95D3BB28D0C88922D1D9022537626D835E67A407C8CDDFE376DE2C46EE4F04F1FEE88D2AABEAA6D09", "balance": "00018CE88D23D425E48205A276400000" }, amount=1000000000000000000000000000 ) ) ) account.add_block( Block( block_data={ "account": "xrb_1jeqoxg7cpo5xgyxhcwzsndeuqp6yyr9m63k8tfu9mskjdfo7iq95p1ktb8j", "destination": "xrb_384jppoodym71cppdj3a9gaim197q9uq365u5jqt6c4zhth13t9as4sj5zs8", "type": "send", "previous": "2453CA428DE7BCA437CDCBCD587646B4E508701E78E5B364F1DF5CF3A80B9F24", "work": "6692fe717be16f9c", "signature": "11E5BFB1304CD12D6960403B98778F76A6023FFFF30174DD21304EE757BD264E8F87FC6649E916BC9DFA861ACB94631C5E388C6ABF412C08891F9818C6CA1B09", "balance": "00000000033A5A7A8401B34F47000000" } ) ) assert account.balance == 999000000000000000000000000 assert account.blocks[1].balance == 999000000000000000000000000 assert account.blocks[1].amount == -1000000000000000000000000
def test_account_complete_blockchain(self): """ Complete account's blockchain one block at a time and check the account's balance after each block """ from tests.wallet.data.account_blocks import ACCOUNTS for account_entry in ACCOUNTS: block_entries = account_entry["blocks"] account_id = account_entry["account_id"] account = Account( account_id=account_id, source=AccountSource.WATCHING ) assert account.balance == 0 for entry in block_entries: block_data = entry["block_data"] link_block_entry = entry.get("link_block", None) link_block = None if link_block_entry: link_block = LinkBlock( block_data=link_block_entry["block_data"], amount=int(link_block_entry["amount"]) ) block = Block( block_data=block_data, link_block=link_block ) account.add_block(block) assert account.balance == int(entry["balance"]) assert account.blocks[-1].balance == int(entry["balance"]) assert account.blocks[-1].tx_type == entry["tx_type"] assert account.blocks[-1].amount == int(entry["amount"])
def test_link_block_data_required(self): with pytest.raises(ValueError) as exc: LinkBlock(amount=10000) assert "'block_data' or 'block' is required" in str(exc.value)