Exemple #1
0
    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)
Exemple #2
0
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]
Exemple #3
0
    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)
Exemple #4
0
    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)
Exemple #5
0
    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"])
                )
Exemple #6
0
    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)
Exemple #7
0
    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)
Exemple #8
0
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
Exemple #9
0
    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"
Exemple #10
0
    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"
Exemple #11
0
    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
Exemple #12
0
    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"])
Exemple #13
0
    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)