Пример #1
0
def test_history(bandwidth_db):
    assert not bandwidth_db.get_history()
    tx1 = BandwidthTransactionData(1, bandwidth_db.my_pub_key, b"a",
                                   EMPTY_SIGNATURE, EMPTY_SIGNATURE, 3000)
    bandwidth_db.BandwidthTransaction.insert(tx1)

    history = bandwidth_db.get_history()
    assert len(history) == 1
    assert history[0]["balance"] == -3000

    tx2 = BandwidthTransactionData(1, b"a", bandwidth_db.my_pub_key,
                                   EMPTY_SIGNATURE, EMPTY_SIGNATURE, 4000)
    bandwidth_db.BandwidthTransaction.insert(tx2)

    history = bandwidth_db.get_history()
    assert len(history) == 2
    assert history[1]["balance"] == 1000

    # Test whether the history is pruned correctly
    bandwidth_db.MAX_HISTORY_ITEMS = 2
    tx3 = BandwidthTransactionData(1, b"a", bandwidth_db.my_pub_key,
                                   EMPTY_SIGNATURE, EMPTY_SIGNATURE, 2000)
    bandwidth_db.BandwidthTransaction.insert(tx3)

    history = bandwidth_db.get_history()
    assert len(history) == 2
Пример #2
0
def test_add_bandwidth_transactions(trust_graph):
    """
    Tests the maximum blocks/transactions that be be present in the graph.
    :return:
    """

    my_pk = trust_graph.root_key
    for _ in range(trust_graph.max_nodes - 1):
        random_node_pk = unhexlify(get_random_node_public_key())
        random_tx = BandwidthTransactionData(1, random_node_pk, my_pk,
                                             EMPTY_SIGNATURE, EMPTY_SIGNATURE,
                                             3000)
        trust_graph.add_bandwidth_transaction(random_tx)

    assert trust_graph.number_of_nodes() == trust_graph.max_nodes

    # Already max number of nodes are added to the graph, adding more should raise an exception
    try:
        tx2 = BandwidthTransactionData(1, my_pk, b"a", EMPTY_SIGNATURE,
                                       EMPTY_SIGNATURE, 2000)
        trust_graph.add_bandwidth_transaction(tx2)
    except TrustGraphException as tge:
        exception_msg = getattr(tge, 'message', repr(tge))
        assert f'Max node peers ({trust_graph.max_nodes}) reached in the graph' in exception_msg
    else:
        assert False, "Expected to fail but did not."
Пример #3
0
    async def test_concurrent_transaction_out_of_order(self):
        """
        Test creating multiple transactions, while the other party is offline and receives messages out of order.
        """
        pk1 = self.nodes[0].my_peer.public_key.key_to_bin()
        pk2 = self.nodes[1].my_peer.public_key.key_to_bin()

        tx1 = BandwidthTransactionData(1, pk1, pk2, EMPTY_SIGNATURE,
                                       EMPTY_SIGNATURE, 1000)
        tx2 = BandwidthTransactionData(2, pk1, pk2, EMPTY_SIGNATURE,
                                       EMPTY_SIGNATURE, 2000)

        # Send them in reverse order
        cache = self.nodes[0].overlay.request_cache.add(
            BandwidthTransactionSignCache(self.nodes[0].overlay, tx1))
        self.nodes[0].overlay.send_transaction(tx2,
                                               self.nodes[1].my_peer.address,
                                               cache.number)
        await self.deliver_messages()

        # This one should be ignored by node 1
        cache = self.nodes[0].overlay.request_cache.add(
            BandwidthTransactionSignCache(self.nodes[0].overlay, tx1))
        self.nodes[0].overlay.send_transaction(tx1,
                                               self.nodes[1].my_peer.address,
                                               cache.number)
        await self.deliver_messages()

        # Both parties should have the transaction with amount 2000 in their database
        assert self.nodes[0].overlay.database.get_total_taken(pk1) == 2000
        assert self.nodes[1].overlay.database.get_total_taken(pk1) == 2000
Пример #4
0
def test_peers_helped_by(bandwidth_db):
    assert bandwidth_db.get_num_peers_helped_by(b"a") == 0
    tx1 = BandwidthTransactionData(1, b"b", b"a", EMPTY_SIGNATURE,
                                   EMPTY_SIGNATURE, 3000)
    bandwidth_db.BandwidthTransaction.insert(tx1)
    assert bandwidth_db.get_num_peers_helped_by(b"a") == 1
    tx2 = BandwidthTransactionData(2, b"c", b"a", EMPTY_SIGNATURE,
                                   EMPTY_SIGNATURE, 3000)
    bandwidth_db.BandwidthTransaction.insert(tx2)
    assert bandwidth_db.get_num_peers_helped_by(b"a") == 2
    tx3 = BandwidthTransactionData(1, b"c", b"b", EMPTY_SIGNATURE,
                                   EMPTY_SIGNATURE, 3000)
    bandwidth_db.BandwidthTransaction.insert(tx3)
    assert bandwidth_db.get_num_peers_helped_by(b"a") == 2
Пример #5
0
 def construct_signed_transaction(self, peer: Peer, amount: int) -> BandwidthTransactionData:
     """
     Construct a new signed bandwidth transaction.
     :param peer: The counterparty of the transaction.
     :param amount: The amount of bytes to payout.
     :return A signed BandwidthTransaction.
     """
     peer_pk = peer.public_key.key_to_bin()
     latest_tx = self.database.get_latest_transaction(self.my_pk, peer_pk)
     total_amount = latest_tx.amount + amount if latest_tx else amount
     next_seq_num = latest_tx.sequence_number + 1 if latest_tx else 1
     tx = BandwidthTransactionData(next_seq_num, self.my_pk, peer_pk, EMPTY_SIGNATURE, EMPTY_SIGNATURE, total_amount)
     tx.sign(self.my_peer.key, as_a=True)
     return tx
Пример #6
0
def test_get_my_latest_transactions(bandwidth_db):
    assert not bandwidth_db.get_my_latest_transactions()

    tx1 = BandwidthTransactionData(1, b"a", bandwidth_db.my_pub_key,
                                   EMPTY_SIGNATURE, EMPTY_SIGNATURE, 3000)
    bandwidth_db.BandwidthTransaction.insert(tx1)
    tx2 = BandwidthTransactionData(1, bandwidth_db.my_pub_key, b"c",
                                   EMPTY_SIGNATURE, EMPTY_SIGNATURE, 3000)
    bandwidth_db.BandwidthTransaction.insert(tx2)
    tx3 = BandwidthTransactionData(1, b"c", b"d", EMPTY_SIGNATURE,
                                   EMPTY_SIGNATURE, 3000)
    bandwidth_db.BandwidthTransaction.insert(tx3)

    assert len(bandwidth_db.get_my_latest_transactions()) == 2
    assert len(bandwidth_db.get_my_latest_transactions(limit=1)) == 1
Пример #7
0
    async def test_ignore_unknown_transaction(self):
        """
        Test whether we are ignoring a transaction that is not in our cache.
        """
        pk1 = self.nodes[0].my_peer.public_key.key_to_bin()
        pk2 = self.nodes[1].my_peer.public_key.key_to_bin()

        tx = BandwidthTransactionData(1, pk1, pk2, EMPTY_SIGNATURE,
                                      EMPTY_SIGNATURE, 1000)
        tx.sign(self.nodes[0].my_peer.key, as_a=True)
        self.nodes[0].overlay.send_transaction(tx,
                                               self.nodes[1].my_peer.address,
                                               1234)
        await self.deliver_messages()
        assert not self.nodes[0].overlay.database.get_latest_transaction(
            pk1, pk2)
Пример #8
0
async def test_totals(bandwidth_db):
    with db_session:
        tx1 = BandwidthTransactionData(1, b"a", b"b", EMPTY_SIGNATURE,
                                       EMPTY_SIGNATURE, 3000)
        bandwidth_db.BandwidthTransaction.insert(tx1)

        assert bandwidth_db.get_total_taken(b"a") == 3000
        assert bandwidth_db.get_total_given(b"a") == 0

        tx2 = BandwidthTransactionData(1, b"b", b"a", EMPTY_SIGNATURE,
                                       EMPTY_SIGNATURE, 4000)
        bandwidth_db.BandwidthTransaction.insert(tx2)

    assert bandwidth_db.get_total_taken(b"a") == 3000
    assert bandwidth_db.get_total_given(b"a") == 4000
    assert bandwidth_db.get_balance(b"a") == 1000
    assert bandwidth_db.get_balance(b"b") == -1000
Пример #9
0
def test_store_large_transaction(bandwidth_db):
    large_tx = BandwidthTransactionData(1, b"a", b"b", EMPTY_SIGNATURE,
                                        EMPTY_SIGNATURE,
                                        1024 * 1024 * 1024 * 3)
    bandwidth_db.BandwidthTransaction.insert(large_tx)

    latest_tx = bandwidth_db.get_latest_transaction(b"a", b"b")
    assert latest_tx
Пример #10
0
def test_get_latest_transaction(bandwidth_db):
    assert not bandwidth_db.get_latest_transaction(b"a", b"b")
    tx1 = BandwidthTransactionData(1, b"a", b"b", EMPTY_SIGNATURE,
                                   EMPTY_SIGNATURE, 3000)
    bandwidth_db.BandwidthTransaction.insert(tx1)

    tx2 = bandwidth_db.get_latest_transaction(b"a", b"b")
    assert tx1 == tx2
    assert tx2.amount == 3000
Пример #11
0
def insert_node_transactions(root_key, session, node_public_key=None, count=1):
    for idx in range(count):
        counterparty = unhexlify(node_public_key if node_public_key else
                                 get_random_node_public_key())
        amount = random.randint(10, 100)
        tx1 = BandwidthTransactionData(idx, root_key, counterparty,
                                       EMPTY_SIGNATURE, EMPTY_SIGNATURE,
                                       amount)
        session.bandwidth_community.database.BandwidthTransaction.insert(tx1)
Пример #12
0
 def get_latest_transaction(
         self, public_key_a: bytes,
         public_key_b: bytes) -> BandwidthTransactionData:
     """
     Return the latest transaction between two parties, or None if no such transaction exists.
     :param public_key_a: The public key of the party transferring the bandwidth.
     :param public_key_b: The public key of the party receiving the bandwidth.
     :return The latest transaction between the two specified parties, or None if no such transaction exists.
     """
     db_obj = self.BandwidthTransaction.get(public_key_a=public_key_a,
                                            public_key_b=public_key_b)
     return BandwidthTransactionData.from_db(db_obj) if db_obj else None
Пример #13
0
def test_sign_transaction():
    key1 = default_eccrypto.generate_key('curve25519')
    key2 = default_eccrypto.generate_key('curve25519')
    tx = BandwidthTransactionData(1, key1.pub().key_to_bin(), key2.pub().key_to_bin(),
                                  EMPTY_SIGNATURE, EMPTY_SIGNATURE, 3000)

    tx.sign(key1, as_a=True)
    assert tx.is_valid()
    assert tx.signature_a != EMPTY_SIGNATURE
    assert tx.signature_b == EMPTY_SIGNATURE

    tx.sign(key2, as_a=False)
    assert tx.is_valid()
    assert tx.signature_a != EMPTY_SIGNATURE
    assert tx.signature_b != EMPTY_SIGNATURE
Пример #14
0
    def received_transaction(self, source_address: Address, data: bytes) -> None:
        """
        Callback when we receive a transaction from another peer.
        :param source_address: The network address of the peer that has sent us the transaction.
        :param data: The serialized, raw data in the packet.
        """
        payload = self._ez_unpack_noauth(BandwidthTransactionPayload, data, global_time=False)
        tx = BandwidthTransactionData.from_payload(payload)

        if not tx.is_valid():
            self.logger.info("Transaction %s not valid, ignoring it", tx)
            return

        if payload.public_key_a == self.my_pk or payload.public_key_b == self.my_pk:
            # This transaction involves this peer.
            latest_tx = self.database.get_latest_transaction(tx.public_key_a, tx.public_key_b)
            if payload.public_key_b == self.my_peer.public_key.key_to_bin():
                from_peer = Peer(payload.public_key_a, source_address)
                if latest_tx:
                    # Check if the amount in the received transaction is higher than the amount of the latest one
                    # in the database.
                    if payload.amount > latest_tx.amount:
                        # Sign it, store it, and send it back
                        tx.sign(self.my_peer.key, as_a=False)
                        self.database.BandwidthTransaction.insert(tx)
                        self.send_transaction(tx, from_peer.address, payload.request_id)
                    else:
                        self.logger.info("Received older bandwidth transaction - sending back the latest one")
                        self.send_transaction(latest_tx, from_peer.address, payload.request_id)
                else:
                    # This transaction is the first one with party A. Sign it, store it, and send it back.
                    tx.sign(self.my_peer.key, as_a=False)
                    self.database.BandwidthTransaction.insert(tx)
                    from_peer = Peer(payload.public_key_a, source_address)
                    self.send_transaction(tx, from_peer.address, payload.request_id)
            elif payload.public_key_a == self.my_peer.public_key.key_to_bin():
                # It seems that we initiated this transaction. Check if we are waiting for it.
                cache = self.request_cache.get("bandwidth-tx-sign", payload.request_id)
                if not cache:
                    self.logger.info("Received bandwidth transaction %s without associated cache entry, ignoring it",
                                     tx)
                    return

                if not latest_tx or (latest_tx and latest_tx.amount >= tx.amount):
                    self.database.BandwidthTransaction.insert(tx)

                cache.future.set_result(tx)
        else:
            # This transaction involves two unknown peers. We can add it to our database.
            self.database.BandwidthTransaction.insert(tx)
Пример #15
0
 def get_latest_transactions(
         self,
         public_key: bytes,
         limit: Optional[int] = 100) -> List[BandwidthTransactionData]:
     """
     Return the latest transactions of a given public key, or an empty list if no transactions exist.
     :param public_key: The public key of the party transferring the bandwidth.
     :param limit: The number of transactions to return. (Default: 100)
     :return The latest transactions of the specified public key, or an empty list if no transactions exist.
     """
     db_txs = select(tx for tx in self.BandwidthTransaction
                     if public_key in (tx.public_key_a, tx.public_key_b))\
         .limit(limit)
     return [BandwidthTransactionData.from_db(db_txn) for db_txn in db_txs]
Пример #16
0
def test_add_transaction(bandwidth_db):
    tx1 = BandwidthTransactionData(1, b"a", b"b", EMPTY_SIGNATURE,
                                   EMPTY_SIGNATURE, 3000)
    bandwidth_db.BandwidthTransaction.insert(tx1)
    assert bandwidth_db.has_transaction(tx1)
    tx2 = BandwidthTransactionData(2, b"a", b"b", EMPTY_SIGNATURE,
                                   EMPTY_SIGNATURE, 4000)
    bandwidth_db.BandwidthTransaction.insert(tx2)

    latest_tx = bandwidth_db.get_latest_transaction(b"a", b"b")
    assert latest_tx
    assert latest_tx.amount == 4000

    # Test storing all transactions
    bandwidth_db.store_all_transactions = True
    tx3 = BandwidthTransactionData(3, b"a", b"b", EMPTY_SIGNATURE,
                                   EMPTY_SIGNATURE, 4000)
    bandwidth_db.BandwidthTransaction.insert(tx3)
    assert len(list(bandwidth_db.BandwidthTransaction.select())) == 2
    assert bandwidth_db.has_transaction(tx2)
    assert bandwidth_db.has_transaction(tx3)

    # Test whether adding a transaction again does not result in an error
    bandwidth_db.BandwidthTransaction.insert(tx2)
Пример #17
0
 def get_my_latest_transactions(
         self,
         limit: Optional[int] = None) -> List[BandwidthTransactionData]:
     """
     Return all latest transactions involving you.
     :param limit: An optional integer, to limit the number of results returned. Pass None to get all results.
     :return A list containing all latest transactions involving you.
     """
     results = []
     db_txs = select(tx for tx in self.BandwidthTransaction
                     if tx.public_key_a == self.my_pub_key or tx.public_key_b == self.my_pub_key)\
         .limit(limit)
     for db_tx in db_txs:
         results.append(BandwidthTransactionData.from_db(db_tx))
     return results
Пример #18
0
def test_get_latest_transactions(bandwidth_db):
    pub_key_a = b"a"
    pub_keys_rest = [b"b", b"c", b"d", b"e", b"f"]

    assert not bandwidth_db.get_latest_transactions(pub_key_a)

    for pub_key in pub_keys_rest:
        seq_number = random.randint(1, 100)
        amount = random.randint(1, 1000)
        tx = BandwidthTransactionData(seq_number, pub_key_a, pub_key,
                                      EMPTY_SIGNATURE, EMPTY_SIGNATURE, amount)
        bandwidth_db.BandwidthTransaction.insert(tx)

    txs = bandwidth_db.get_latest_transactions(pub_key_a)
    assert len(txs) == len(pub_keys_rest)
Пример #19
0
    def on_payout(self, source_address: Address, data: bytes) -> None:
        """
        We received a payout from another peer.
        :param source_address: The address of the peer that sent us this payout.
        :param data: The serialized, raw data.
        """
        if not self.bandwidth_community:
            self.logger.warning(
                "Got payout while not having a bandwidth community running!")
            return

        payload = self._ez_unpack_noauth(BandwidthTransactionPayload,
                                         data,
                                         global_time=False)
        tx = BandwidthTransactionData.from_payload(payload)

        if not tx.is_valid():
            self.logger.info(
                "Received invalid bandwidth transaction in tunnel community - ignoring it"
            )
            return

        from_peer = Peer(payload.public_key_a, source_address)
        my_pk = self.my_peer.public_key.key_to_bin()
        latest_tx = self.bandwidth_community.database.get_latest_transaction(
            self.my_peer.public_key.key_to_bin(),
            from_peer.public_key.key_to_bin())
        if payload.circuit_id != 0 and tx.public_key_b == my_pk and (
                not latest_tx or latest_tx.amount < tx.amount):
            # Sign it and send it back
            tx.sign(self.my_peer.key, as_a=False)
            self.bandwidth_community.database.BandwidthTransaction.insert(tx)

            response_payload = BandwidthTransactionPayload.from_transaction(
                tx, 0, payload.base_amount)
            packet = self._ez_pack(self._prefix, 30, [response_payload], False)
            self.send_packet(from_peer, packet)
        elif payload.circuit_id == 0 and tx.public_key_a == my_pk:
            if not latest_tx or (latest_tx and latest_tx.amount >= tx.amount):
                self.bandwidth_community.database.BandwidthTransaction.insert(
                    tx)

        # Send the next payout
        if payload.circuit_id in self.relay_from_to and tx.amount > payload.base_amount:
            relay = self.relay_from_to[payload.circuit_id]
            self._logger.info("Sending next payout to peer %s", relay.peer)
            self.do_payout(relay.peer, relay.circuit_id,
                           payload.base_amount * 2, payload.base_amount)
Пример #20
0
def test_is_valid():
    key1 = default_eccrypto.generate_key('curve25519')
    key2 = default_eccrypto.generate_key('curve25519')
    tx = BandwidthTransactionData(1, key1.pub().key_to_bin(), key2.pub().key_to_bin(),
                                  EMPTY_SIGNATURE, EMPTY_SIGNATURE, 3000)

    assert tx.is_valid()  # No signatures have been computed so far

    tx.signature_a = b'a' * 32
    assert not tx.is_valid()

    tx.signature_a = EMPTY_SIGNATURE
    tx.signature_b = b'a' * 32
    assert not tx.is_valid()

    tx.signature_a = EMPTY_SIGNATURE
    tx.signature_b = EMPTY_SIGNATURE
    tx.sequence_number = -1
    assert not tx.is_valid()
Пример #21
0
async def test_trustview_response(enable_api, mock_ipv8, session,
                                  mock_bootstrap):
    """
    Test whether the trust graph response is correctly returned.

    Scenario: A graph with 3 nodes in each layers (layer 1: friends, layer 2: fofs, layer 3: fofofs).
    The current implementation of trust graph only considers two layers, therefore,
    number of nodes in the graph = 1 (root node) + 3 (friends) + 3 (fofs) = 7
    number of transactions in the graphs = 3 (root node to friends) + 3 (friends) * 3 (fofs) = 12
    """
    root_key = session.bandwidth_community.my_pk
    friends = [
        "4c69624e61434c504b3a2ee28ce24a2259b4e585b81106cdff4359fcf48e93336c11d133b01613f30b03b4db06df27"
        "80daac2cdf2ee60be611bf7367a9c1071ac50d65ca5858a50e9578",
        "4c69624e61434c504b3a5368c7b39a82063e29576df6d74fba3e0dba3af8e7a304b553b71f08ea6a0730e8cef767a4"
        "85dc6f390b6da5631f772941ea69ce2c098d802b7a28b500edf2b3",
        "4c69624e61434c504b3a0f3f6318e49ffeb0a160e7fcac5c1d3337ba409b45e1371ddca5e3b364ebdd1b73c775318a"
        "533a25335a5c36ae3695f1c3036b651893659fbf2e1f2bce66cf65",
    ]

    fofs = [
        "4c69624e61434c504b3a2ee28ce24a2259b4e585b81106cdff4359fcf48e93336c11d133b01613f30b03b4db06df27"
        "80daac2cdf2ee60be611bf7367a9c1071ac50d65ca5858a50e9579",
        "4c69624e61434c504b3a5368c7b39a82063e29576df6d74fba3e0dba3af8e7a304b553b71f08ea6a0730e8cef767a4"
        "85dc6f390b6da5631f772941ea69ce2c098d802b7a28b500edf2b4",
        "4c69624e61434c504b3a0f3f6318e49ffeb0a160e7fcac5c1d3337ba409b45e1371ddca5e3b364ebdd1b73c775318a"
        "533a25335a5c36ae3695f1c3036b651893659fbf2e1f2bce66cf66",
    ]

    fofofs = [
        "4c69624e61434c504b3a2ee28ce24a2259b4e585b81106cdff4359fcf48e93336c11d133b01613f30b03b4db06df27"
        "80daac2cdf2ee60be611bf7367a9c1071ac50d65ca5858a50e9580",
        "4c69624e61434c504b3a5368c7b39a82063e29576df6d74fba3e0dba3af8e7a304b553b71f08ea6a0730e8cef767a4"
        "85dc6f390b6da5631f772941ea69ce2c098d802b7a28b500edf2b5",
        "4c69624e61434c504b3a0f3f6318e49ffeb0a160e7fcac5c1d3337ba409b45e1371ddca5e3b364ebdd1b73c775318a"
        "533a25335a5c36ae3695f1c3036b651893659fbf2e1f2bce66cf67",
    ]

    def verify_response(response_json):
        expected_nodes = 1 + len(friends) + len(fofs)
        expected_txns = len(friends) + len(friends) * len(fofs)

        assert response_json['graph']
        assert response_json['num_tx'] == expected_txns
        assert len(response_json['graph']['node']) == expected_nodes

    for pub_key in friends:
        tx1 = BandwidthTransactionData(1, root_key, unhexlify(pub_key),
                                       EMPTY_SIGNATURE, EMPTY_SIGNATURE, 3000)
        session.bandwidth_community.database.BandwidthTransaction.insert(tx1)

    for friend in friends:
        for fof in fofs:
            tx2 = BandwidthTransactionData(1, unhexlify(friend),
                                           unhexlify(fof), EMPTY_SIGNATURE,
                                           EMPTY_SIGNATURE, 3000)
            session.bandwidth_community.database.BandwidthTransaction.insert(
                tx2)

    for fof in fofs:
        for fofof in fofofs:
            tx3 = BandwidthTransactionData(1, unhexlify(fof), unhexlify(fofof),
                                           EMPTY_SIGNATURE, EMPTY_SIGNATURE,
                                           3000)
            session.bandwidth_community.database.BandwidthTransaction.insert(
                tx3)

    response = await do_request(session, 'trustview', expected_code=200)
    verify_response(response)