Esempio n. 1
0
    def test_create_link_to_com_chain(self, monkeypatch):
        """
        Test creating a linked half that points back towards a previous block
        """
        key = default_eccrypto.generate_key(u"curve25519")
        com_key = default_eccrypto.generate_key(u"curve25519").pub().key_to_bin()
        db = MockDBManager()
        com_link = Links(((1, ShortKey("30303030")),))
        link = FakeBlock(com_id=com_key, links=com_link)

        monkeypatch.setattr(
            MockDBManager,
            "get_chain",
            lambda _, chain_id: MockChain() if chain_id == com_key else None,
        )
        monkeypatch.setattr(
            MockChain, "consistent_terminal", Links((link.com_dot,)),
        )
        block = BamiBlock.create(
            b"test", encode_raw({"id": 42}), db, key.pub().key_to_bin(), com_id=com_key
        )

        # include the personal community

        # Attach to the
        assert block.links == Links((link.com_dot,))
        assert block.previous == Links((GENESIS_DOT,))
        assert block.sequence_number == GENESIS_SEQ
        assert block.com_seq_num == link.com_seq_num + 1
        assert block.public_key == key.pub().key_to_bin()
        assert block.signature == EMPTY_SIG
        assert block.type == b"test"
        assert block.transaction == encode_raw({"id": 42})
        assert block.com_id == com_key
Esempio n. 2
0
 def test_risky_spend(self):
     self.chain_id = self.minter
     spend_value = Decimal(10.00, self.con)
     spend_dot = Dot((1, "11111"))
     self.state.apply_spend(
         self.chain_id,
         GENESIS_LINK,
         GENESIS_LINK,
         spend_dot,
         self.spender,
         self.receiver,
         spend_value,
     )
     assert float(self.state.get_balance(self.spender)) == -10
     # Next spend - tries to pretend as if hasn't happen
     self.new_spend_value = Decimal(6.00, self.con)
     self.new_spend_dot = Dot((2, "22222"))
     self.state.apply_spend(
         self.chain_id,
         Links((spend_dot,)),
         Links((spend_dot,)),
         self.new_spend_dot,
         self.spender,
         self.receiver,
         self.new_spend_value,
     )
     # As the value is less -> the balance will not change until confirmed, or rejected
     assert float(self.state.get_balance(self.spender)) == -10
Esempio n. 3
0
class StdVals:
    terminal = Links(((5, b"test1"), ))
    term_bits = (True, )
    holes = Ranges(())
    incon = Links(())
    conflicts = {}
    con_terminal = terminal
Esempio n. 4
0
    def test_create_next_pers(self, monkeypatch):
        """
        Test creating a block that points towards a previous block
        """
        db = MockDBManager()
        prev = FakeBlock()

        monkeypatch.setattr(
            MockDBManager,
            "get_chain",
            lambda _, chain_id: MockChain(),
        )
        monkeypatch.setattr(
            MockChain,
            "consistent_terminal",
            Links((prev.pers_dot, )),
        )

        block = BamiBlock.create(b"test", encode_raw({b"id": 42}), db,
                                 prev.public_key)

        assert block.previous == Links((prev.pers_dot, ))
        assert block.sequence_number == prev.sequence_number + 1
        assert block.public_key == prev.public_key
        assert block.signature == EMPTY_SIG
        assert block.type == b"test"
        assert block.transaction == encode_raw({b"id": 42})
        assert block.com_id == EMPTY_PK
        assert block.com_seq_num == UNKNOWN_SEQ
Esempio n. 5
0
class InconVals:
    terminal = Links(((0, b"gen"), (5, b"test1")))
    term_bits = (
        True,
        False,
    )
    holes = Ranges(((1, 4), ))
    incon = Links(((4, b"test1"), ))
    con_terminal = Links(((0, b"gen"), ))
    conflicts = {(5, b"test1"): {1: (b"gen", ), 5: (b"test2", )}}
Esempio n. 6
0
    def test_spend_fork(self):
        value = Decimal(1, self.con)
        dot = Dot((1, b"123123"))
        chain_id = self.spender

        self.state.apply_spend(
            chain_id,
            GENESIS_LINK,
            GENESIS_LINK,
            dot,
            self.spender,
            self.receiver,
            value,
        )
        assert float(self.state.get_balance(self.spender)) == -1
        new_dot = Dot((1, b"5464646"))
        self.state.apply_spend(
            chain_id,
            GENESIS_LINK,
            GENESIS_LINK,
            new_dot,
            self.spender,
            self.receiver,
            value,
        )
        assert float(self.state.get_balance(self.spender)) == -2

        assert self.state.is_chain_forked(chain_id, self.spender)
        assert self.state.was_chain_forked(chain_id, self.spender)

        # Fix the fork:
        f_dot = Dot((2, b"000000"))
        value = Decimal(3, self.con)
        self.state.apply_spend(
            chain_id,
            Links((dot, new_dot)),
            Links((dot, new_dot)),
            f_dot,
            self.spender,
            self.receiver,
            value,
        )
        assert float(self.state.get_balance(self.spender)) == -3

        assert not self.state.is_chain_forked(chain_id, self.spender)
        assert self.state.was_chain_forked(chain_id, self.spender)
Esempio n. 7
0
def create_block_batch(com_id, num_blocks=100, txs=None):
    blocks = []
    last_block_point = GENESIS_LINK
    for k in range(num_blocks):
        tx = txs[k] if txs else None
        blk = FakeBlock(com_id=com_id, links=last_block_point, transaction=tx)
        blocks.append(blk)
        last_block_point = Links(((blk.com_seq_num, blk.short_hash), ))
    return blocks
Esempio n. 8
0
    def test_prev_iter(self, create_batches, insert_function, chain):
        batches = create_batches(num_batches=2, num_blocks=10)
        prev_links = Links((GENESIS_DOT, ))
        for i in range(len(batches[0])):
            wrap_return(insert_function(chain, [batches[0][i]]))

            assert len(chain.get_prev_links(chain.terminal[0])) == 1
            assert chain.get_prev_links(chain.terminal[0]) == prev_links

            prev_links = chain.terminal
Esempio n. 9
0
def test_compare_frontiers():
    val = StdVals
    f = Frontier(val.terminal, val.holes, val.incon)
    f2 = copy(f)
    f2.terminal = Links(((6, b"test2"), ))

    assert f != f2
    assert f2 > f

    inc_f = Frontier(InconVals.terminal, InconVals.holes, InconVals.incon)
    assert f > inc_f
    assert f2 > inc_f
Esempio n. 10
0
 def process_block_unordered(self, blk: BamiBlock, peer: Peer) -> None:
     self.unordered_notifier.notify(blk.com_prefix + blk.com_id, blk)
     if peer != self.my_peer:
         frontier = Frontier(Links((blk.com_dot,)), holes=(), inconsistencies=())
         subcom_id = blk.com_prefix + blk.com_id
         processing_queue = self.incoming_frontier_queue(subcom_id)
         if not processing_queue:
             raise UnknownChainException(
                 "Cannot process block received block with unknown chain. {subcom_id}".format(
                     subcom_id=subcom_id
                 )
             )
         processing_queue.put_nowait((peer, frontier, True))
Esempio n. 11
0
    def test_valid_spend_with_reject(self):
        chain_id, value, spend_dot = self.test_mint_and_spend()

        reject_dot = Dot((3, "33333"))
        # Add confirmation from the counter-party
        self.state.apply_reject(
            chain_id,
            self.receiver,
            Links((spend_dot,)),
            reject_dot,
            self.spender,
            spend_dot,
        )
        # As the transaction is confirmed, inconsistency is resolved
        assert float(self.state.get_balance(self.spender)) == 3 + value
        assert float(self.state.get_balance(self.receiver)) == 0
Esempio n. 12
0
    def test_create_genesis(self):
        """
        Test creating a genesis block
        """
        key = default_eccrypto.generate_key(u"curve25519")
        db = MockDBManager()
        block = BamiBlock.create(b"test", encode_raw({b"id": 42}), db,
                                 key.pub().key_to_bin())

        assert block.previous == Links((GENESIS_DOT, ))
        assert block.sequence_number == GENESIS_SEQ
        assert block.public_key == key.pub().key_to_bin()
        assert block.signature == EMPTY_SIG
        assert block.type == b"test"
        assert block.transaction == encode_raw({b"id": 42})
        assert block.com_id == EMPTY_PK
        assert block.com_seq_num == UNKNOWN_SEQ
Esempio n. 13
0
    def test_risky_spend_with_reject(self):
        self.test_risky_spend()

        reject_dot = Dot((3, "33333"))
        # Add confirmation from the counter-party
        self.state.apply_reject(
            self.chain_id,
            self.receiver,
            Links((self.new_spend_dot,)),
            reject_dot,
            self.spender,
            self.new_spend_dot,
        )
        # As the transaction is rejected - the effect of it is reverted to the previous stable state - zero.
        assert float(self.state.get_balance(self.spender)) == 0
        assert float(self.state.get_balance(self.receiver)) == 0
        assert self.state.was_balance_negative(self.spender)
Esempio n. 14
0
    def test_risky_spend_with_confirm(self):
        self.test_risky_spend()

        confirm_dot = Dot((3, "33333"))
        # Add confirmation from the counter-party
        self.state.apply_confirm(
            self.chain_id,
            self.receiver,
            Links((self.new_spend_dot,)),
            confirm_dot,
            self.spender,
            self.new_spend_dot,
            self.new_spend_value,
        )
        # As the transaction is confirmed, inconsistency is resolved
        assert float(self.state.get_balance(self.spender)) == -6
        assert float(self.state.get_balance(self.receiver)) == 6
        assert self.state.was_balance_negative(self.spender)
Esempio n. 15
0
def create_block_batch(com_id, num_blocks=100):
    """
    Create a given amount of blocks. Each block points to the previous one.

    Args:
        com_id: The community identifier of the block batch.
        num_blocks: The number of blocks to create.

    Returns: A list with blocks.

    """
    blocks = []
    last_block_point = GENESIS_LINK
    for k in range(num_blocks):
        blk = FakeBlock(com_id=com_id, links=last_block_point, transaction=None)
        blocks.append(blk)
        last_block_point = Links(((blk.com_seq_num, blk.short_hash),))
    return blocks
Esempio n. 16
0
    def test_insert_with_merge_block(self, create_batches, insert_function,
                                     chain):
        batches = create_batches(num_batches=2, num_blocks=10)

        last_blk1 = batches[0][-1]
        last_blk2 = batches[1][-1]

        dot1 = (last_blk1.com_seq_num, last_blk1.short_hash)
        dot2 = (last_blk2.com_seq_num, last_blk2.short_hash)

        vals = wrap_return(insert_function(chain, batches[0]))
        assert len(vals) == 10
        assert vals[0][0] == 1 and vals[-1][0] == 10

        merge_block = FakeBlock(links=Links((dot1, dot2)))
        chain.add_block(merge_block.links, merge_block.com_seq_num,
                        merge_block.hash)

        vals = wrap_return(insert_function(chain, batches[1]))
        assert len(vals) == 11
        assert vals[0][0] == 1 and vals[-1][0] == 11

        assert len(list(chain.get_dots_by_seq_num(11))) == 1
Esempio n. 17
0
    def test_add_claim(self):
        value = Decimal(12.11, self.con)
        dot = Dot((1, "123123"))
        chain_id = self.spender

        self.state.apply_spend(
            chain_id,
            GENESIS_LINK,
            GENESIS_LINK,
            dot,
            self.spender,
            self.receiver,
            value,
        )
        assert self.state.last_spend_values[self.spender][self.receiver][dot] == value
        assert float(self.state.get_balance(self.spender)) == -12.11

        claim_dot = Dot((1, "2323"))

        self.state.apply_confirm(
            chain_id, self.receiver, Links((dot,)), claim_dot, self.spender, dot, value
        )
        assert self.state.last_spend_values[self.spender][self.receiver][dot] == value
        assert float(self.state.get_balance(self.receiver)) == 12.11
Esempio n. 18
0
    def test_mint_and_spend(self):
        chain_id = self.minter
        value = Decimal(15.00, self.con)
        dot = Dot((1, "123123"))

        self.state.apply_mint(chain_id, dot, GENESIS_LINK, self.minter, value)
        assert self.state.get_balance(self.minter) == value
        assert not self.state.is_chain_forked(chain_id, self.minter)

        spend_value = Decimal(12.00, self.con)
        spend_dot = Dot((2, "23123"))
        self.state.apply_spend(
            chain_id,
            GENESIS_LINK,
            Links((dot,)),
            spend_dot,
            self.spender,
            self.receiver,
            spend_value,
        )
        assert float(self.state.get_balance(self.spender)) == 3
        assert not self.state.is_chain_forked(chain_id, self.spender)
        assert not self.state.was_chain_forked(chain_id, self.spender)
        return chain_id, spend_value, spend_dot
Esempio n. 19
0
    def create(
        cls,
        block_type: bytes,
        transaction: bytes,
        database: BaseDB,
        public_key: bytes,
        com_prefix: bytes = b"",
        com_id: bytes = None,
        com_links: Links = None,
        pers_links: Links = None,
        use_consistent_links: bool = True,
    ):
        """
        Create PlexusBlock wrt local database knowledge.

        Args:
            block_type: type of the block in bytes
            transaction: transaction blob bytes
            database: local database with chains
            public_key: public key of the block creator
            com_prefix: prefix for the chain identification [optional]
            com_id: id of the community which block is part of [optional]
            com_links: Explicitly link with these blocks [optional]
            pers_links: Create a block at a certain [optional]
            use_consistent_links: Build on top of blocks that are known. By default: True

        Returns:
            PlexusBlock

        """

        if public_key == com_id:
            full_pers_chain_id = com_prefix + public_key
        else:
            full_pers_chain_id = public_key
        personal_chain = database.get_chain(full_pers_chain_id)
        # Decide to link blocks in the personal chain:
        if not personal_chain:
            # There are no blocks in the personal chain yet
            last_link = Links((GENESIS_DOT, ))
        else:
            last_link = (personal_chain.consistent_terminal
                         if use_consistent_links else personal_chain.terminal)

        # Fork personal chain at the
        if pers_links:
            # There is an explicit link for the previous link
            last_link = pers_links

        per_seq_num = max(last_link)[0] + 1

        # TODO: Add link filtering and choose links
        ret = cls()
        ret.type = block_type
        ret.transaction = transaction
        ret.sequence_number = per_seq_num
        ret.previous = last_link

        # --- Community related logic ---
        if com_id:
            ret.com_id = com_id
            # There is community specified => will base block on the latest known information + filters
            if com_links:
                last_com_links = com_links
                com_seq_num = max(last_com_links)[0]
            else:
                com_chain = database.get_chain(com_prefix + com_id)
                if not com_chain:
                    last_com_links = Links((GENESIS_DOT, ))
                else:
                    last_com_links = (com_chain.consistent_terminal
                                      if use_consistent_links else
                                      com_chain.terminal)
                # TODO: add link filtering here
                com_seq_num = max(last_com_links)[0] + 1

            ret.links = last_com_links
            ret.com_seq_num = com_seq_num
            ret.com_id = com_id
            ret.com_prefix = com_prefix

        ret._links = encode_links(ret.links)
        ret._previous = encode_links(ret.previous)

        ret.public_key = public_key
        ret.signature = EMPTY_SIG
        ret.hash = ret.calculate_hash()
        return ret
Esempio n. 20
0
def test_encode_decode_links(keys_fixture):
    links = Links(((1, shorten(keys_fixture)), ))
    raw_bytes = encode_links(links)
    assert decode_links(raw_bytes) == links
Esempio n. 21
0
 def test_empty_terminal(self):
     chain = Chain()
     assert chain.consistent_terminal == Links((GENESIS_DOT, ))
Esempio n. 22
0
    def test_add_invalid_claim(self):
        value = Decimal(1, self.con)
        dot = Dot((1, "123123"))
        chain_id = self.spender

        self.state.apply_spend(
            chain_id,
            GENESIS_LINK,
            GENESIS_LINK,
            dot,
            self.spender,
            self.receiver,
            value,
        )
        assert self.state.last_spend_values[self.spender][self.receiver][dot] == value
        assert float(self.state.get_balance(self.spender)) == -1

        new_dot = Dot((1, "223123"))
        self.state.apply_spend(
            chain_id,
            GENESIS_LINK,
            GENESIS_LINK,
            new_dot,
            self.spender,
            self.receiver,
            value,
        )
        assert self.state.last_spend_values[self.spender][self.receiver][dot] == value
        assert float(self.state.get_balance(self.spender)) == -2
        assert self.state.was_chain_forked(chain_id, self.spender)

        claim_dot = Dot((2, "33323"))
        with pytest.raises(InvalidClaimException):
            # Should raise exception as the claim links are not correct
            self.state.apply_confirm(
                chain_id,
                self.receiver,
                GENESIS_LINK,
                claim_dot,
                self.spender,
                dot,
                value,
            )
        self.state.apply_confirm(
            chain_id, self.receiver, Links((dot,)), claim_dot, self.spender, dot, value
        )

        assert self.state.last_spend_values[self.spender][self.receiver][dot] == value
        assert float(self.state.get_balance(self.receiver)) == 1
        with pytest.raises(InvalidClaimException):
            # Double claim - should raise exception
            self.state.apply_confirm(
                chain_id,
                self.receiver,
                Links((claim_dot,)),
                claim_dot,
                self.spender,
                dot,
                value,
            )
        assert float(self.state.get_balance(self.receiver)) == 1
        assert not self.state.was_chain_forked(chain_id, self.receiver)

        # Add inconsistent claim
        inconsistent_value = Decimal(100, self.con)
        with pytest.raises(InconsistentClaimException):
            self.state.apply_confirm(
                chain_id,
                self.receiver,
                Links((claim_dot,)),
                claim_dot,
                self.spender,
                new_dot,
                inconsistent_value,
            )
        assert float(self.state.get_balance(self.receiver)) == 1
        assert not self.state.was_chain_forked(chain_id, self.receiver)
Esempio n. 23
0
    def test_state_updates(self):
        chain_id = self.minter
        value = Decimal(12.00, self.con)
        dot = Dot((1, b"123123"))

        self.state.apply_mint(
            chain_id, dot, GENESIS_LINK, self.minter, value, store_update=True
        )
        assert self.state.get_balance(self.minter) == value
        assert not self.state.is_chain_forked(chain_id, self.minter)
        spend_value = Decimal(12.00, self.con)
        spend_dot = Dot((2, b"23123"))
        self.state.apply_spend(
            chain_id,
            GENESIS_LINK,
            Links((dot,)),
            spend_dot,
            self.spender,
            self.receiver,
            spend_value,
            store_status_update=True,
        )
        assert float(self.state.get_balance(self.spender)) == 0
        assert not self.state.is_chain_forked(chain_id, self.spender)

        claim_dot = Dot((3, b"23323"))

        self.state.apply_confirm(
            chain_id,
            self.receiver,
            Links((spend_dot,)),
            claim_dot,
            self.spender,
            spend_dot,
            spend_value,
            store_update=True,
        )

        v = self.state.get_closest_peers_status(chain_id, 1)
        assert v is not None
        assert v[0] == 1
        assert len(v[1]) == 1
        assert v[1].get(shorten(self.spender)) == (True, True)

        v = self.state.get_closest_peers_status(chain_id, 2)
        assert v is not None
        assert (
            (v[0] == 2)
            and (len(v[1]) == 1)
            and (v[1].get(shorten(self.spender)) == (True, True))
        )

        v = self.state.get_closest_peers_status(chain_id, 3)
        assert v is not None
        assert (
            v[0] == 3
            and len(v[1]) == 2
            and (v[1].get(shorten(self.spender)) == (True, True))
            and (v[1].get(shorten(self.receiver)) == (True, True))
        )

        assert v[1] == self.state.get_last_peer_status(chain_id)
Esempio n. 24
0
 def test_empty_terminal(self, chain):
     assert chain.consistent_terminal == Links((GENESIS_DOT, ))