Esempio n. 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
Esempio n. 2
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)
Esempio n. 3
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
Esempio n. 4
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
Esempio n. 5
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
Esempio n. 6
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
Esempio n. 7
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
Esempio n. 8
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
Esempio n. 9
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
Esempio n. 10
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]
Esempio n. 11
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
Esempio n. 12
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)
Esempio n. 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
Esempio n. 14
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
Esempio n. 15
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)
Esempio n. 16
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)
Esempio n. 17
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()
Esempio n. 18
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 from peer %s:%d - "
                            "sending back the latest one", *from_peer.address)
                        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)