diff --git a/.github/workflows/scripttest.yml b/.github/workflows/scripttest.yml
index 9da846f4a46..68eec17c475 100644
--- a/.github/workflows/scripttest.yml
+++ b/.github/workflows/scripttest.yml
@@ -42,10 +42,10 @@ jobs:
with:
path: ./src
- - name: run_bandwidth_crawler.py
+ - name: run_crawler.py
uses: ./.github/actions/timeout
with:
- command: python ./scripts/bandwidth_crawler/run_bandwidth_crawler.py --fragile
+ command: python ./scripts/crawler/run_crawler.py --fragile
duration: ${{inputs.duration}}
- name: run_exit_node.py
diff --git a/scripts/application_tester/tribler_apptester/config/tribler_config.spec b/scripts/application_tester/tribler_apptester/config/tribler_config.spec
index b9c4bc41530..32d418adea6 100644
--- a/scripts/application_tester/tribler_apptester/config/tribler_config.spec
+++ b/scripts/application_tester/tribler_apptester/config/tribler_config.spec
@@ -22,9 +22,6 @@ ec_keypair_filename = string(default='ec_multichain.pem')
testnet_keypair_filename = string(default='ec_trustchain_testnet.pem')
testnet = boolean(default=False)
-[bandwidth_accounting]
-testnet = boolean(default=False)
-
[bootstrap]
enabled = boolean(default=True)
max_download_rate = integer(min=1, default=1000000)
diff --git a/scripts/bandwidth_crawler/README.md b/scripts/crawler/README.md
similarity index 73%
rename from scripts/bandwidth_crawler/README.md
rename to scripts/crawler/README.md
index 60e572d85da..658140ffde6 100644
--- a/scripts/bandwidth_crawler/README.md
+++ b/scripts/crawler/README.md
@@ -1,4 +1,4 @@
-# Bandwidth Crawler
+# Crawler
## Requirements
@@ -8,5 +8,5 @@
## Execution
```shell
-python3 run_bandwidth_crawler.py
+python3 run_crawler.py
```
\ No newline at end of file
diff --git a/scripts/bandwidth_crawler/run_bandwidth_crawler.py b/scripts/crawler/run_crawler.py
similarity index 80%
rename from scripts/bandwidth_crawler/run_bandwidth_crawler.py
rename to scripts/crawler/run_crawler.py
index 4561e3f8360..2dcac089d84 100644
--- a/scripts/bandwidth_crawler/run_bandwidth_crawler.py
+++ b/scripts/crawler/run_crawler.py
@@ -1,5 +1,7 @@
"""
-This executable script starts a Tribler instance and joins the BandwidthAccountingCommunity.
+This is an example of a Tribler crawler. It was originally written by @devos50
+to crawl the BandwidthCommunity's data and was later adapted to serve
+as just an example of a generic Tribler crawler.
"""
import argparse
import logging
@@ -8,7 +10,6 @@
from asyncio import ensure_future, get_event_loop
from pathlib import Path
-from tribler.core.components.bandwidth_accounting.bandwidth_accounting_component import BandwidthAccountingComponent
from tribler.core.components.ipv8.ipv8_component import Ipv8Component
from tribler.core.components.key.key_component import KeyComponent
from tribler.core.components.session import Session
@@ -16,6 +17,19 @@
from tribler.core.utilities.utilities import make_async_loop_fragile
+async def crawler_session(session_config: TriblerConfig):
+ session = Session(
+ config=session_config,
+ components=[
+ KeyComponent(),
+ Ipv8Component(),
+ # Put Your Component Here
+ ])
+ signal.signal(signal.SIGTERM, lambda signum, stack: session.shutdown_event.set)
+ async with session:
+ await session.shutdown_event.wait()
+
+
class PortAction(argparse.Action):
def __call__(self, _, namespace, value, option_string=None):
if not 0 < value < 2 ** 16:
@@ -23,14 +37,6 @@ def __call__(self, _, namespace, value, option_string=None):
setattr(namespace, self.dest, value)
-async def crawler_session(session_config: TriblerConfig):
- session = Session(session_config,
- [KeyComponent(), Ipv8Component(), BandwidthAccountingComponent(crawler_mode=True)])
- signal.signal(signal.SIGTERM, lambda signum, stack: session.shutdown_event.set)
- async with session:
- await session.shutdown_event.wait()
-
-
if __name__ == "__main__":
parser = argparse.ArgumentParser(description=('Start a crawler in the bandwidth accounting community'))
parser.add_argument('--statedir', '-s', default='bw_crawler', type=str, help='Use an alternate statedir')
@@ -45,13 +51,10 @@ async def crawler_session(session_config: TriblerConfig):
config = TriblerConfig.load(state_dir=state_dir)
config.tunnel_community.enabled = False
- config.libtorrent.enabled = False
config.bootstrap.enabled = False
- config.chant.enabled = False
config.torrent_checking.enabled = False
config.api.http_enabled = True
config.api.http_port = args.restapi
- config.bandwidth_accounting.outgoing_query_interval = 5
loop = get_event_loop()
if args.fragile:
diff --git a/scripts/exit_node/run_exit_node.py b/scripts/exit_node/run_exit_node.py
index c7c220337ce..8150aeb51f2 100644
--- a/scripts/exit_node/run_exit_node.py
+++ b/scripts/exit_node/run_exit_node.py
@@ -15,7 +15,6 @@
from ipv8.util import run_forever
from tribler.core import notifications
-from tribler.core.components.bandwidth_accounting.bandwidth_accounting_component import BandwidthAccountingComponent
from tribler.core.components.ipv8.ipv8_component import Ipv8Component
from tribler.core.components.key.key_component import KeyComponent
from tribler.core.components.restapi.restapi_component import RESTComponent
@@ -33,7 +32,6 @@ def components_gen():
yield KeyComponent()
yield RESTComponent()
yield Ipv8Component()
- yield BandwidthAccountingComponent()
yield TunnelsComponent()
diff --git a/src/run_tribler_headless.py b/src/run_tribler_headless.py
index 3f07fdce012..37932a1a73d 100644
--- a/src/run_tribler_headless.py
+++ b/src/run_tribler_headless.py
@@ -114,7 +114,6 @@ async def signal_handler(sig):
if options.testnet:
config.tunnel_community.testnet = True
config.chant.testnet = True
- config.bandwidth_accounting.testnet = True
self.session = Session(config, components=list(components_gen(config)))
try:
diff --git a/src/tribler/core/components/bandwidth_accounting/__init__.py b/src/tribler/core/components/bandwidth_accounting/__init__.py
deleted file mode 100644
index e69de29bb2d..00000000000
diff --git a/src/tribler/core/components/bandwidth_accounting/bandwidth_accounting_component.py b/src/tribler/core/components/bandwidth_accounting/bandwidth_accounting_component.py
deleted file mode 100644
index 9686af225e9..00000000000
--- a/src/tribler/core/components/bandwidth_accounting/bandwidth_accounting_component.py
+++ /dev/null
@@ -1,55 +0,0 @@
-from tribler.core.components.bandwidth_accounting.community.bandwidth_accounting_community import (
- BandwidthAccountingCommunity,
- BandwidthAccountingTestnetCommunity,
-)
-from tribler.core.components.bandwidth_accounting.db.database import BandwidthDatabase
-from tribler.core.components.component import Component
-from tribler.core.components.ipv8.ipv8_component import Ipv8Component
-from tribler.core.utilities.simpledefs import STATEDIR_DB_DIR
-
-
-class BandwidthAccountingComponent(Component):
- community: BandwidthAccountingCommunity = None
- _ipv8_component: Ipv8Component = None
- database: BandwidthDatabase = None
-
- def __init__(self, crawler_mode=False):
- super().__init__()
- self.crawler_mode = crawler_mode
-
- async def run(self):
- await super().run()
- self._ipv8_component = await self.require_component(Ipv8Component)
-
- config = self.session.config
- if config.general.testnet or config.bandwidth_accounting.testnet:
- bandwidth_cls = BandwidthAccountingTestnetCommunity
- else:
- bandwidth_cls = BandwidthAccountingCommunity
-
- if self.crawler_mode:
- store_all_transactions = True
- unlimited_peers = True
- else:
- store_all_transactions = False
- unlimited_peers = False
-
- db_name = "bandwidth_gui_test.db" if config.gui_test_mode else f"{bandwidth_cls.DB_NAME}.db"
- database_path = config.state_dir / STATEDIR_DB_DIR / db_name
- self.database = BandwidthDatabase(database_path, self._ipv8_component.peer.public_key.key_to_bin(),
- store_all_transactions=store_all_transactions)
-
- kwargs = {"max_peers": -1} if unlimited_peers else {}
- self.community = bandwidth_cls(self._ipv8_component.peer,
- self._ipv8_component.ipv8.endpoint,
- self._ipv8_component.ipv8.network,
- settings=config.bandwidth_accounting,
- database=self.database,
- **kwargs)
-
- self._ipv8_component.initialise_community_by_default(self.community)
-
- async def shutdown(self):
- await super().shutdown()
- if self._ipv8_component and self.community:
- await self._ipv8_component.unload_community(self.community)
diff --git a/src/tribler/core/components/bandwidth_accounting/community/__init__.py b/src/tribler/core/components/bandwidth_accounting/community/__init__.py
deleted file mode 100644
index e69de29bb2d..00000000000
diff --git a/src/tribler/core/components/bandwidth_accounting/community/bandwidth_accounting_community.py b/src/tribler/core/components/bandwidth_accounting/community/bandwidth_accounting_community.py
deleted file mode 100644
index 4c3dd4df1a7..00000000000
--- a/src/tribler/core/components/bandwidth_accounting/community/bandwidth_accounting_community.py
+++ /dev/null
@@ -1,206 +0,0 @@
-from __future__ import annotations
-
-from asyncio import Future
-from binascii import unhexlify
-from random import Random
-from typing import Dict
-
-from ipv8.peer import Peer
-from ipv8.requestcache import RequestCache
-from ipv8.types import Address
-
-from tribler.core.components.bandwidth_accounting.community.cache import BandwidthTransactionSignCache
-from tribler.core.components.bandwidth_accounting.community.payload import (
- BandwidthTransactionPayload,
- BandwidthTransactionQueryPayload,
-)
-from tribler.core.components.bandwidth_accounting.db.database import BandwidthDatabase
-from tribler.core.components.bandwidth_accounting.db.transaction import BandwidthTransactionData, EMPTY_SIGNATURE
-from tribler.core.components.ipv8.tribler_community import TriblerCommunity
-from tribler.core.utilities.unicode import hexlify
-
-
-class BandwidthAccountingCommunity(TriblerCommunity):
- """
- Community around bandwidth accounting and payouts.
- """
- community_id = unhexlify('79b25f2867739261780faefede8f25038de9975d')
- DB_NAME = 'bandwidth'
- version = b'\x02'
-
- def __init__(self, *args, **kwargs) -> None:
- """
- Initialize the community.
- :param persistence: The database that stores transactions, will be created if not provided.
- :param database_path: The path at which the database will be created. Defaults to the current working directory.
- """
- self.database: BandwidthDatabase = kwargs.pop('database', None)
- self.random = Random()
-
- super().__init__(*args, **kwargs)
-
- self.request_cache = RequestCache()
- self.my_pk = self.my_peer.public_key.key_to_bin()
-
- self.add_message_handler(BandwidthTransactionPayload, self.received_transaction)
- self.add_message_handler(BandwidthTransactionQueryPayload, self.received_query)
-
- self.register_task("query_peers", self.query_random_peer, interval=self.settings.outgoing_query_interval)
-
- self.logger.info("Started bandwidth accounting community with public key %s", hexlify(self.my_pk))
-
- 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
-
- def do_payout(self, peer: Peer, amount: int) -> Future:
- """
- Conduct a payout with a given amount of bytes to a peer.
- :param peer: The counterparty of the payout.
- :param amount: The amount of bytes to payout.
- :return A Future that fires when the counterparty has acknowledged the payout.
- """
- tx = self.construct_signed_transaction(peer, amount)
- self.database.BandwidthTransaction.insert(tx)
- cache = self.request_cache.add(BandwidthTransactionSignCache(self, tx))
- self.send_transaction(tx, peer.address, cache.number)
-
- return cache.future
-
- def send_transaction(self, transaction: BandwidthTransactionData, address: Address, request_id: int) -> None:
- """
- Send a provided transaction to another party.
- :param transaction: The BandwidthTransaction to send to the other party.
- :param peer: The IP address and port of the peer.
- :param request_id: The identifier of the message, is usually provided by a request cache.
- """
- payload = BandwidthTransactionPayload.from_transaction(transaction, request_id)
- packet = self._ez_pack(self._prefix, 1, [payload], False)
- self.endpoint.send(address, packet)
-
- 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)
-
- def query_random_peer(self) -> None:
- """
- Query a random peer neighbouring peer and ask their bandwidth transactions.
- """
- peers = list(self.network.verified_peers)
- if peers:
- random_peer = self.random.choice(peers)
- self.query_transactions(random_peer)
-
- def query_transactions(self, peer: Peer) -> None:
- """
- Query the transactions of a specific peer and ask for their bandwidth transactions.
- :param peer: The peer to send the query to.
- """
- self.logger.info("Querying the transactions of peer %s:%d", *peer.address)
- payload = BandwidthTransactionQueryPayload()
- packet = self._ez_pack(self._prefix, 2, [payload], False)
- self.endpoint.send(peer.address, packet)
-
- def received_query(self, source_address: Address, data: bytes) -> None:
- """
- We received a query from another peer.
- :param source_address: The network address of the peer that has sent us the query.
- :param data: The serialized, raw data in the packet.
- """
- my_txs = self.database.get_my_latest_transactions(limit=self.settings.max_tx_returned_in_query)
- self.logger.debug("Sending %d bandwidth transaction(s) to peer %s:%d", len(my_txs), *source_address)
- for tx in my_txs:
- self.send_transaction(tx, source_address, 0)
-
- def get_statistics(self) -> Dict:
- """
- Return a dictionary with bandwidth statistics, including the total amount of bytes given and taken, and the
- number of unique peers you helped/that helped you.
- :return: A dictionary with statistics.
- """
- my_pk = self.my_peer.public_key.key_to_bin()
- return {
- "id": hexlify(my_pk),
- "total_given": self.database.get_total_given(my_pk),
- "total_taken": self.database.get_total_taken(my_pk),
- "num_peers_helped": self.database.get_num_peers_helped(my_pk),
- "num_peers_helped_by": self.database.get_num_peers_helped_by(my_pk)
- }
-
- async def unload(self) -> None:
- """
- Unload this community by shutting down the request cache and database.
- """
- self.logger.info("Unloading the bandwidth accounting community.")
-
- await self.request_cache.shutdown()
- self.database.shutdown()
-
- await super().unload()
-
-
-class BandwidthAccountingTestnetCommunity(BandwidthAccountingCommunity):
- """
- This community defines the testnet for bandwidth accounting.
- """
- DB_NAME = 'bandwidth_testnet'
- community_id = unhexlify('e7de42f46f9ef225f4a5fc32ed0a0ce9a8ea4af6')
diff --git a/src/tribler/core/components/bandwidth_accounting/community/cache.py b/src/tribler/core/components/bandwidth_accounting/community/cache.py
deleted file mode 100644
index c58682b11b7..00000000000
--- a/src/tribler/core/components/bandwidth_accounting/community/cache.py
+++ /dev/null
@@ -1,42 +0,0 @@
-from __future__ import annotations
-
-from asyncio import Future
-from typing import TYPE_CHECKING
-
-from ipv8.requestcache import RandomNumberCache
-
-from tribler.core.components.bandwidth_accounting.db.transaction import BandwidthTransactionData
-
-if TYPE_CHECKING:
- from tribler.core.components.bandwidth_accounting.community.bandwidth_accounting_community import \
- BandwidthAccountingCommunity
-
-
-class BandwidthTransactionSignCache(RandomNumberCache):
- """
- This cache keeps track of pending bandwidth transaction signature requests.
- """
-
- def __init__(self, community: BandwidthAccountingCommunity, transaction: BandwidthTransactionData) -> None:
- """
- Initialize the cache.
- :param community: The bandwidth community associated with this cache.
- :param transaction: The transaction that will be signed by the counterparty.
- """
- super().__init__(community.request_cache, "bandwidth-tx-sign")
- self.transaction = transaction
- self.future = Future()
- self.register_future(self.future)
-
- @property
- def timeout_delay(self) -> float:
- """
- :return The timeout of this sign cache, defaults to one hour.
- """
- return 3600.0
-
- def on_timeout(self) -> None:
- """
- Invoked when the cache times out.
- """
- self._logger.info("Sign request for transaction %s timed out!", self.transaction)
diff --git a/src/tribler/core/components/bandwidth_accounting/community/payload.py b/src/tribler/core/components/bandwidth_accounting/community/payload.py
deleted file mode 100644
index 9dcb024facb..00000000000
--- a/src/tribler/core/components/bandwidth_accounting/community/payload.py
+++ /dev/null
@@ -1,35 +0,0 @@
-from __future__ import annotations
-
-from ipv8.messaging.lazy_payload import VariablePayload, vp_compile
-
-
-@vp_compile
-class BandwidthTransactionPayload(VariablePayload):
- """
- Payload for a message containing a bandwidth transaction.
- """
- msg_id = 1
- format_list = ['I', '74s', '74s', '64s', '64s', 'Q', 'Q', 'I']
- names = ["sequence_number", "public_key_a", "public_key_b", "signature_a", "signature_b", "amount",
- "timestamp", "request_id"]
-
- @classmethod
- def from_transaction(cls, transaction, request_id: int) -> BandwidthTransactionPayload:
- return BandwidthTransactionPayload(
- transaction.sequence_number,
- transaction.public_key_a,
- transaction.public_key_b,
- transaction.signature_a,
- transaction.signature_b,
- transaction.amount,
- transaction.timestamp,
- request_id
- )
-
-
-@vp_compile
-class BandwidthTransactionQueryPayload(VariablePayload):
- """
- (empty) payload for an outgoing query to fetch transactions by the counterparty.
- """
- msg_id = 2
diff --git a/src/tribler/core/components/bandwidth_accounting/db/__init__.py b/src/tribler/core/components/bandwidth_accounting/db/__init__.py
deleted file mode 100644
index e69de29bb2d..00000000000
diff --git a/src/tribler/core/components/bandwidth_accounting/db/database.py b/src/tribler/core/components/bandwidth_accounting/db/database.py
deleted file mode 100644
index 2863285b717..00000000000
--- a/src/tribler/core/components/bandwidth_accounting/db/database.py
+++ /dev/null
@@ -1,191 +0,0 @@
-from pathlib import Path
-from typing import List, Optional, Union
-
-from pony.orm import count, db_session, desc, select
-
-from tribler.core.components.bandwidth_accounting.db import history, misc, transaction as db_transaction
-from tribler.core.components.bandwidth_accounting.db.transaction import BandwidthTransactionData
-from tribler.core.utilities.db_corruption_handling.base import handle_db_if_corrupted
-from tribler.core.utilities.pony_utils import TrackedDatabase
-from tribler.core.utilities.utilities import MEMORY_DB
-
-
-class BandwidthDatabase:
- """
- Simple database that stores bandwidth transactions in Tribler as a work graph.
- """
- CURRENT_DB_VERSION = 9
- MAX_HISTORY_ITEMS = 100 # The maximum number of history items to store.
-
- def __init__(self, db_path: Union[Path, type(MEMORY_DB)], my_pub_key: bytes,
- store_all_transactions: bool = False) -> None:
- """
- Sets up the persistence layer ready for use.
- :param db_path: The full path of the database.
- :param my_pub_key: The public key of the user operating the database.
- :param store_all_transactions: Whether we store all pairwise transactions in the database. This is disabled by
- default and used for data collection purposes.
- """
- self.my_pub_key = my_pub_key
- self.store_all_transactions = store_all_transactions
-
- self.database = TrackedDatabase()
-
- # This attribute is internally called by Pony on startup, though pylint cannot detect it
- # with the static analysis.
- # pylint: disable=unused-variable
-
- @self.database.on_connect
- def sqlite_sync_pragmas(_, connection):
- cursor = connection.cursor()
- cursor.execute("PRAGMA journal_mode = WAL")
- cursor.execute("PRAGMA synchronous = 1")
- cursor.execute("PRAGMA temp_store = 2")
- # pylint: enable=unused-variable
-
- self.MiscData = misc.define_binding(self.database)
- self.BandwidthTransaction = db_transaction.define_binding(self)
- self.BandwidthHistory = history.define_binding(self)
-
- if db_path is MEMORY_DB:
- create_db = True
- db_path_string = ":memory:"
- else:
- # We need to handle the database corruption case before determining the state of the create_db flag.
- handle_db_if_corrupted(db_path)
- create_db = not db_path.is_file()
- db_path_string = str(db_path)
-
- self.database.bind(provider='sqlite', filename=db_path_string, create_db=create_db, timeout=120.0)
- self.database.generate_mapping(create_tables=create_db)
-
- if create_db:
- with db_session:
- self.MiscData(name="db_version", value=str(self.CURRENT_DB_VERSION))
-
- def has_transaction(self, transaction: BandwidthTransactionData) -> bool:
- """
- Return whether a transaction is persisted to the database.
- :param transaction: The transaction to check.
- :return: A boolean value, indicating whether we have the transaction in the database or not.
- """
- return self.BandwidthTransaction.exists(public_key_a=transaction.public_key_a,
- public_key_b=transaction.public_key_b,
- sequence_number=transaction.sequence_number)
-
- @db_session
- 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
-
- @db_session
- 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_tx = select(tx for tx in self.BandwidthTransaction
- if public_key_a == tx.public_key_a and public_key_b == tx.public_key_b) \
- .order_by(lambda tx: desc(tx.sequence_number)) \
- .first()
-
- return BandwidthTransactionData.from_db(db_tx) if db_tx else None
-
- @db_session
- 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]
-
- @db_session
- def get_total_taken(self, public_key: bytes) -> int:
- """
- Return the total amount of bandwidth taken by a given party.
- :param public_key: The public key of the peer of which we want to determine the total taken.
- :return The total amount of bandwidth taken by the specified peer, in bytes.
- """
- return select(transaction.amount for transaction in self.BandwidthTransaction
- if transaction.public_key_a == public_key).sum()
-
- @db_session
- def get_total_given(self, public_key: bytes) -> int:
- """
- Return the total amount of bandwidth given by a given party.
- :param public_key: The public key of the peer of which we want to determine the total given.
- :return The total amount of bandwidth given by the specified peer, in bytes.
- """
- return select(transaction.amount for transaction in self.BandwidthTransaction
- if transaction.public_key_b == public_key).sum()
-
- @db_session
- def get_balance(self, public_key: bytes) -> int:
- """
- Return the bandwidth balance (total given - total taken) of a specific peer.
- :param public_key: The public key of the peer of which we want to determine the balance.
- :return The bandwidth balance the specified peer, in bytes.
- """
- return self.get_total_given(public_key) - self.get_total_taken(public_key)
-
- def get_my_balance(self) -> int:
- """
- Return your bandwidth balance, which is the total amount given minus the total amount taken.
- :return Your bandwidth balance, in bytes.
- """
- return self.get_balance(self.my_pub_key)
-
- @db_session
- def get_num_peers_helped(self, public_key: bytes) -> int:
- """
- Return the number of unique peers that a peer with the provided public key has helped.
- :param public_key: The public key of the peer of which we want to determine this number.
- :return The unique number of peers helped by the specified peer.
- """
- result = list(select(count(g.public_key_b) for g in self.BandwidthTransaction if g.public_key_a == public_key))
- return result[0]
-
- @db_session
- def get_num_peers_helped_by(self, public_key: bytes) -> int:
- """
- Return the number of unique peers that a peer with the provided public key has been helped by.
- :param public_key: The public key of the peer of which we want to determine this number.
- :return The unique number of peers that helped the specified peer.
- """
- result = list(select(count(g.public_key_a) for g in self.BandwidthTransaction if g.public_key_b == public_key))
- return result[0]
-
- @db_session
- def get_history(self) -> List:
- """
- Get the history of your bandwidth balance as an ordered list.
- :return A list. Each item in this list contains a timestamp and a balance.
- """
- history = []
- for history_item in self.BandwidthHistory.select().order_by(self.BandwidthHistory.timestamp):
- history.append({"timestamp": history_item.timestamp, "balance": history_item.balance})
-
- return history
-
- def shutdown(self) -> None:
- """
- Shutdown the database.
- """
- self.database.disconnect()
diff --git a/src/tribler/core/components/bandwidth_accounting/db/history.py b/src/tribler/core/components/bandwidth_accounting/db/history.py
deleted file mode 100644
index 7c299bf51bd..00000000000
--- a/src/tribler/core/components/bandwidth_accounting/db/history.py
+++ /dev/null
@@ -1,17 +0,0 @@
-from pony.orm import PrimaryKey, Required
-
-
-def define_binding(bandwidth_database):
- db = bandwidth_database.database
-
- class BandwidthHistory(db.Entity):
- """
- This ORM class represents a mutation of ones bandwidth balance.
- We store the last 100 mutations in ones bandwidth balance.
- """
-
- rowid = PrimaryKey(int, auto=True)
- timestamp = Required(int, size=64)
- balance = Required(int, size=64)
-
- return BandwidthHistory
diff --git a/src/tribler/core/components/bandwidth_accounting/db/misc.py b/src/tribler/core/components/bandwidth_accounting/db/misc.py
deleted file mode 100644
index 1adf5f4c50d..00000000000
--- a/src/tribler/core/components/bandwidth_accounting/db/misc.py
+++ /dev/null
@@ -1,12 +0,0 @@
-from pony.orm import Optional, PrimaryKey
-
-
-def define_binding(db):
- class MiscData(db.Entity):
- """
- This binding is used to store all kinds of values, like DB version, counters, etc.
- """
- name = PrimaryKey(str)
- value = Optional(str)
-
- return MiscData
diff --git a/src/tribler/core/components/bandwidth_accounting/db/transaction.py b/src/tribler/core/components/bandwidth_accounting/db/transaction.py
deleted file mode 100644
index 8db476b320b..00000000000
--- a/src/tribler/core/components/bandwidth_accounting/db/transaction.py
+++ /dev/null
@@ -1,174 +0,0 @@
-"""
-This file defines the required data structures for the bandwidth accounting mechanism.
-Note that we define two different class types of BandwidthTransaction: one for the object that resides outside the
-Pony database and another one that represents the class inside Pony.
-We make this separation to workaround the fact that Pony does not support objects that are created outside a database
-context.
-"""
-from __future__ import annotations
-
-import time
-from dataclasses import dataclass, field
-from typing import Dict
-
-from ipv8.keyvault.crypto import default_eccrypto
-from ipv8.keyvault.keys import Key
-from ipv8.messaging.serialization import default_serializer
-from pony.orm import PrimaryKey, Required, db_session
-
-from tribler.core.components.bandwidth_accounting.community.payload import BandwidthTransactionPayload
-
-EMPTY_SIGNATURE = b'0' * 64
-
-
-@dataclass
-class BandwidthTransactionData:
- """
- This class defines a data class for a bandwidth transaction.
- """
- sequence_number: int
- public_key_a: bytes
- public_key_b: bytes
- signature_a: bytes
- signature_b: bytes
- amount: int
- timestamp: int = field(default_factory=lambda: int(round(time.time() * 1000)))
-
- def pack(self, signature_a=True, signature_b=True) -> bytes:
- """
- Encode this block for transport.
- :param signature_a: False to pack EMPTY_SIG in the location of signature A, true to pack the signature A field.
- :param signature_b: False to pack EMPTY_SIG in the location of signature B, true to pack the signature B field.
- :return: bytes object the data was packed into.
- """
- args = [self.sequence_number, self.public_key_a, self.public_key_b,
- self.signature_a if signature_a else EMPTY_SIGNATURE,
- self.signature_b if signature_b else EMPTY_SIGNATURE, self.amount, self.timestamp]
- return default_serializer.pack_serializable(BandwidthTransactionPayload(*args, 0))
-
- def sign(self, key: Key, as_a: bool) -> None:
- """
- Signs this block with the given key
- :param key: The key to sign this block with.
- :param as_a: Whether we are signing this block as party A or B.
- """
- if as_a:
- # Party A is the first to sign the transaction
- self.signature_a = default_eccrypto.create_signature(
- key, self.pack(signature_a=False, signature_b=False))
- else:
- # Party B is the first to sign the transaction
- self.signature_b = default_eccrypto.create_signature(
- key, self.pack(signature_b=False))
-
- def is_valid(self) -> bool:
- """
- Validate the signatures in the transaction.
- return: True if the transaction is valid, False otherwise
- """
- if self.signature_a != EMPTY_SIGNATURE:
- # Verify signature A
- pck = self.pack(signature_a=False, signature_b=False)
- valid_signature = default_eccrypto.is_valid_signature(
- default_eccrypto.key_from_public_bin(self.public_key_a), pck, self.signature_a)
- if not valid_signature:
- return False
-
- if self.signature_b != EMPTY_SIGNATURE:
- # Verify signature B
- pck = self.pack(signature_b=False)
- valid_signature = default_eccrypto.is_valid_signature(
- default_eccrypto.key_from_public_bin(self.public_key_b), pck, self.signature_b)
- if not valid_signature:
- return False
-
- if self.sequence_number < 1:
- return False
-
- return True
-
- @classmethod
- def from_payload(cls, payload: BandwidthTransactionPayload):
- """
- Create a block according to a given payload.
- This method can be used when receiving a block from the network.
- :param payload: The payload to convert to a transaction.
- :return A BandwidthTransaction, constructed from the provided payload.
- """
- return cls(payload.sequence_number, payload.public_key_a, payload.public_key_b,
- payload.signature_a, payload.signature_b, payload.amount, payload.timestamp)
-
- @classmethod
- def from_db(cls, db_obj) -> BandwidthTransactionData:
- """
- Return a BandwidthTransaction object from a database object.
- :param db_obj: The BandwidthTransaction object to convert.
- :return A BandwidthTransaction object, based on the database object.
- """
- return BandwidthTransactionData(db_obj.sequence_number, db_obj.public_key_a, db_obj.public_key_b,
- db_obj.signature_a, db_obj.signature_b, db_obj.amount, db_obj.timestamp)
-
- def get_db_kwargs(self) -> Dict:
- """
- Return the database arguments for easy insertion in a Pony database.
- :return A dictionary with keyword arguments for database insertion.
- """
- return {
- "sequence_number": self.sequence_number,
- "public_key_a": self.public_key_a,
- "public_key_b": self.public_key_b,
- "signature_a": self.signature_a,
- "signature_b": self.signature_b,
- "amount": self.amount,
- "timestamp": self.timestamp
- }
-
-
-def define_binding(bandwidth_database):
- db = bandwidth_database.database
-
- class BandwidthTransaction(db.Entity):
- """
- This class describes a bandwidth transaction that resides in the database.
- """
- sequence_number = Required(int)
- public_key_a = Required(bytes, index=True)
- public_key_b = Required(bytes, index=True)
- signature_a = Required(bytes)
- signature_b = Required(bytes)
- amount = Required(int, size=64)
- timestamp = Required(int, size=64)
- PrimaryKey(sequence_number, public_key_a, public_key_b)
-
- @classmethod
- @db_session(optimistic=False)
- def insert(cls, transaction: BandwidthTransaction) -> None:
- """
- Insert a BandwidthTransaction object in the database.
- Remove the last transaction with that specific counterparty while doing so.
- :param transaction: The transaction to insert in the database.
- """
- if not bandwidth_database.store_all_transactions:
- # Make sure to only store the latest pairwise transaction.
- for tx in cls.select(
- lambda c: c.public_key_a == transaction.public_key_a and
- c.public_key_b == transaction.public_key_b):
- tx.delete()
- db.commit()
- cls(**transaction.get_db_kwargs())
- elif not bandwidth_database.has_transaction(transaction):
- # We store all transactions and it does not exist yet - insert it.
- cls(**transaction.get_db_kwargs())
-
- if transaction.public_key_a == bandwidth_database.my_pub_key or \
- transaction.public_key_b == bandwidth_database.my_pub_key:
- # Update the balance history
- timestamp = int(round(time.time() * 1000))
- db.BandwidthHistory(timestamp=timestamp, balance=bandwidth_database.get_my_balance())
- num_entries = db.BandwidthHistory.select().count()
- if num_entries > bandwidth_database.MAX_HISTORY_ITEMS:
- # Delete the entry with the lowest timestamp
- entry = list(db.BandwidthHistory.select().order_by(db.BandwidthHistory.timestamp))[0]
- entry.delete()
-
- return BandwidthTransaction
diff --git a/src/tribler/core/components/bandwidth_accounting/restapi/__init__.py b/src/tribler/core/components/bandwidth_accounting/restapi/__init__.py
deleted file mode 100644
index e69de29bb2d..00000000000
diff --git a/src/tribler/core/components/bandwidth_accounting/restapi/bandwidth_endpoint.py b/src/tribler/core/components/bandwidth_accounting/restapi/bandwidth_endpoint.py
deleted file mode 100644
index 025312b2893..00000000000
--- a/src/tribler/core/components/bandwidth_accounting/restapi/bandwidth_endpoint.py
+++ /dev/null
@@ -1,64 +0,0 @@
-from aiohttp import web
-from aiohttp_apispec import docs
-from ipv8.REST.schema import schema
-from marshmallow.fields import Integer, String
-
-from tribler.core.components.bandwidth_accounting.community.bandwidth_accounting_community import (
- BandwidthAccountingCommunity,
-)
-from tribler.core.components.restapi.rest.rest_endpoint import RESTEndpoint, RESTResponse
-from tribler.core.utilities.utilities import froze_it
-
-
-@froze_it
-class BandwidthEndpoint(RESTEndpoint):
- """
- This endpoint is responsible for handing requests for bandwidth accounting data.
- """
- path = '/bandwidth'
-
- def __init__(self, bandwidth_community: BandwidthAccountingCommunity):
- super().__init__()
- self.bandwidth_community = bandwidth_community
-
- def setup_routes(self) -> None:
- self.app.add_routes([web.get('/statistics', self.get_statistics)])
- self.app.add_routes([web.get('/history', self.get_history)])
-
- @docs(
- tags=["Bandwidth"],
- summary="Return statistics about the bandwidth community.",
- responses={
- 200: {
- "schema": schema(BandwidthStatisticsResponse={
- 'statistics': schema(BandwidthStatistics={
- 'id': String,
- 'num_peers_helped': Integer,
- 'num_peers_helped_by': Integer,
- 'total_taken': Integer,
- 'total_given': Integer
- })
- })
- }
- }
- )
- async def get_statistics(self, request) -> RESTResponse:
- return RESTResponse({'statistics': self.bandwidth_community.get_statistics()})
-
- @docs(
- tags=["Bandwidth"],
- summary="Return a list of the balance history.",
- responses={
- 200: {
- "schema": schema(BandwidthHistoryResponse={
- "history": [schema(BandwidthHistoryItem={
- "timestamp": Integer,
- "balance": Integer
- })
- ]
- })
- }
- }
- )
- async def get_history(self, request) -> RESTResponse:
- return RESTResponse({'history': self.bandwidth_community.database.get_history()})
diff --git a/src/tribler/core/components/bandwidth_accounting/settings.py b/src/tribler/core/components/bandwidth_accounting/settings.py
deleted file mode 100644
index 3df107daf12..00000000000
--- a/src/tribler/core/components/bandwidth_accounting/settings.py
+++ /dev/null
@@ -1,9 +0,0 @@
-from pydantic import Field
-
-from tribler.core.config.tribler_config_section import TriblerConfigSection
-
-
-class BandwidthAccountingSettings(TriblerConfigSection):
- testnet: bool = Field(default=False, env='BANDWIDTH_TESTNET')
- outgoing_query_interval: int = 30 # The interval at which we send out queries to other peers, in seconds.
- max_tx_returned_in_query: int = 10 # The maximum number of bandwidth transactions to return in response to a query.
diff --git a/src/tribler/core/components/bandwidth_accounting/tests/__init__.py b/src/tribler/core/components/bandwidth_accounting/tests/__init__.py
deleted file mode 100644
index e69de29bb2d..00000000000
diff --git a/src/tribler/core/components/bandwidth_accounting/tests/test_bandwidth_accounting_component.py b/src/tribler/core/components/bandwidth_accounting/tests/test_bandwidth_accounting_component.py
deleted file mode 100644
index 5d9dd822e28..00000000000
--- a/src/tribler/core/components/bandwidth_accounting/tests/test_bandwidth_accounting_component.py
+++ /dev/null
@@ -1,16 +0,0 @@
-from tribler.core.components.bandwidth_accounting.bandwidth_accounting_component import BandwidthAccountingComponent
-from tribler.core.components.ipv8.ipv8_component import Ipv8Component
-from tribler.core.components.key.key_component import KeyComponent
-from tribler.core.components.session import Session
-
-
-# pylint: disable=protected-access
-
-
-async def test_bandwidth_accounting_component(tribler_config):
- components = [KeyComponent(), Ipv8Component(), BandwidthAccountingComponent()]
- async with Session(tribler_config, components) as session:
- comp = session.get_instance(BandwidthAccountingComponent)
- assert comp.started_event.is_set() and not comp.failed
- assert comp.community
- assert comp._ipv8_component
diff --git a/src/tribler/core/components/bandwidth_accounting/tests/test_bandwidth_endpoint.py b/src/tribler/core/components/bandwidth_accounting/tests/test_bandwidth_endpoint.py
deleted file mode 100644
index d1b9078509e..00000000000
--- a/src/tribler/core/components/bandwidth_accounting/tests/test_bandwidth_endpoint.py
+++ /dev/null
@@ -1,79 +0,0 @@
-import pytest
-from ipv8.keyvault.crypto import default_eccrypto
-from ipv8.peer import Peer
-
-from tribler.core.components.bandwidth_accounting.community.bandwidth_accounting_community import (
- BandwidthAccountingCommunity,
-)
-from tribler.core.components.bandwidth_accounting.db.database import BandwidthDatabase
-from tribler.core.components.bandwidth_accounting.db.transaction import BandwidthTransactionData, EMPTY_SIGNATURE
-from tribler.core.components.bandwidth_accounting.restapi.bandwidth_endpoint import BandwidthEndpoint
-from tribler.core.components.bandwidth_accounting.settings import BandwidthAccountingSettings
-from tribler.core.components.ipv8.adapters_tests import TriblerMockIPv8
-from tribler.core.components.restapi.rest.base_api_test import do_request
-from tribler.core.utilities.unicode import hexlify
-
-
-# pylint: disable=redefined-outer-name
-@pytest.fixture
-def peer():
- return Peer(default_eccrypto.generate_key("curve25519"), address=("1.2.3.4", 5))
-
-
-@pytest.fixture
-def bandwidth_database(tmp_path, peer):
- return BandwidthDatabase(db_path=tmp_path / "bandwidth.db", my_pub_key=peer.public_key.key_to_bin())
-
-
-@pytest.fixture
-async def bw_community(bandwidth_database, peer):
- ipv8 = TriblerMockIPv8(peer, BandwidthAccountingCommunity,
- database=bandwidth_database,
- settings=BandwidthAccountingSettings())
- community = ipv8.get_overlay(BandwidthAccountingCommunity)
- yield community
- await ipv8.stop()
-
-
-@pytest.fixture
-async def bw_endpoint(bw_community):
- endpoint = BandwidthEndpoint(bw_community)
- endpoint.setup_routes()
- return endpoint
-
-
-async def test_get_statistics(bw_endpoint, bw_community, aiohttp_client):
- """
- Testing whether the API returns the correct statistics
- """
- bw_endpoint.bandwidth_community = bw_community
- my_pk = bw_community.database.my_pub_key
- tx1 = BandwidthTransactionData(1, b"a", my_pk, EMPTY_SIGNATURE, EMPTY_SIGNATURE, 3000)
- tx2 = BandwidthTransactionData(1, my_pk, b"a", EMPTY_SIGNATURE, EMPTY_SIGNATURE, 2000)
- bw_community.database.BandwidthTransaction.insert(tx1)
- bw_community.database.BandwidthTransaction.insert(tx2)
-
- response_dict = await do_request(await aiohttp_client(bw_endpoint.app), 'statistics', expected_code=200)
- assert "statistics" in response_dict
- stats = response_dict["statistics"]
- assert stats["id"] == hexlify(my_pk)
- assert stats["total_given"] == 3000
- assert stats["total_taken"] == 2000
- assert stats["num_peers_helped"] == 1
- assert stats["num_peers_helped_by"] == 1
-
-
-async def test_get_history(bw_endpoint, bw_community, aiohttp_client):
- """
- Testing whether the API returns the correct bandwidth balance history
- """
- bw_endpoint.bandwidth_community = bw_community
- my_pk = bw_community.my_peer.public_key.key_to_bin()
- tx1 = BandwidthTransactionData(1, b"a", my_pk, EMPTY_SIGNATURE, EMPTY_SIGNATURE, 3000)
- tx2 = BandwidthTransactionData(1, my_pk, b"a", EMPTY_SIGNATURE, EMPTY_SIGNATURE, 2000)
- bw_community.database.BandwidthTransaction.insert(tx1)
- bw_community.database.BandwidthTransaction.insert(tx2)
-
- response_dict = await do_request(await aiohttp_client(bw_endpoint.app), 'history', expected_code=200)
- assert "history" in response_dict
- assert len(response_dict["history"]) == 2
diff --git a/src/tribler/core/components/bandwidth_accounting/tests/test_community.py b/src/tribler/core/components/bandwidth_accounting/tests/test_community.py
deleted file mode 100644
index d5560318c04..00000000000
--- a/src/tribler/core/components/bandwidth_accounting/tests/test_community.py
+++ /dev/null
@@ -1,156 +0,0 @@
-import unittest.mock
-
-from ipv8.keyvault.crypto import default_eccrypto
-from ipv8.peer import Peer
-
-from tribler.core.components.bandwidth_accounting.community.bandwidth_accounting_community import (
- BandwidthAccountingCommunity,
-)
-from tribler.core.components.bandwidth_accounting.community.cache import BandwidthTransactionSignCache
-from tribler.core.components.bandwidth_accounting.db.database import BandwidthDatabase
-from tribler.core.components.bandwidth_accounting.db.transaction import BandwidthTransactionData, EMPTY_SIGNATURE
-from tribler.core.components.bandwidth_accounting.settings import BandwidthAccountingSettings
-from tribler.core.components.ipv8.adapters_tests import TriblerMockIPv8, TriblerTestBase
-from tribler.core.utilities.utilities import MEMORY_DB
-
-ID1, ID2, ID3 = range(3)
-
-
-class TestBandwidthAccountingCommunity(TriblerTestBase):
-
- def setUp(self):
- super().setUp()
- self.initialize(BandwidthAccountingCommunity, 2)
-
- def create_node(self, *args, **kwargs):
- peer = Peer(default_eccrypto.generate_key("curve25519"), address=("1.2.3.4", 5))
- db = BandwidthDatabase(db_path=MEMORY_DB, my_pub_key=peer.public_key.key_to_bin())
- ipv8 = TriblerMockIPv8(peer, BandwidthAccountingCommunity, database=db,
- settings=BandwidthAccountingSettings())
- return ipv8
-
- def database(self, i):
- return self.overlay(i).database
-
- def add_cache(self, i, cache):
- return self.overlay(i).request_cache.add(cache)
-
- async def test_single_transaction(self):
- """
- Test a simple transaction between two parties.
- """
- await self.overlay(ID1).do_payout(self.peer(ID2), 1024)
-
- assert self.database(ID1).get_total_taken(self.key_bin(ID1)) == 1024
- assert self.database(ID2).get_total_taken(self.key_bin(ID1)) == 1024
-
- async def test_multiple_transactions(self):
- """
- Test multiple, subsequent transactions between two parties.
- """
- await self.overlay(ID1).do_payout(self.peer(ID2), 500)
- await self.overlay(ID1).do_payout(self.peer(ID2), 1500)
-
- assert self.database(ID1).get_total_taken(self.key_bin(ID1)) == 2000
- assert self.database(ID2).get_total_taken(self.key_bin(ID1)) == 2000
-
- async def test_bilateral_transaction(self):
- """
- Test creating a transaction from A to B and one from B to A.
- """
- await self.overlay(ID1).do_payout(self.peer(ID2), 500)
- await self.overlay(ID2).do_payout(self.peer(ID1), 1500)
-
- assert self.database(ID1).get_total_taken(self.key_bin(ID1)) == 500
- assert self.database(ID2).get_total_taken(self.key_bin(ID1)) == 500
- assert self.database(ID1).get_total_taken(self.key_bin(ID2)) == 1500
- assert self.database(ID2).get_total_taken(self.key_bin(ID2)) == 1500
-
- async def test_bilateral_transaction_timestamps(self):
- """
- Test whether the timestamps are different for transactions created at different times.
-
- We do not depend on chance and ensure that `time.time()` is different between calls.
- """
- with unittest.mock.patch('time.time') as fake_time:
- fake_time.return_value = 10.0
- tx1 = await self.overlay(ID1).do_payout(self.peer(ID2), 500)
-
- with unittest.mock.patch('time.time') as fake_time:
- fake_time.return_value = 11.0
- tx2 = await self.overlay(ID1).do_payout(self.peer(ID2), 500)
-
- assert tx1.timestamp != tx2.timestamp
-
- async def test_invalid_transaction(self):
- """
- Test sending a transaction with an invalid signature to the counterparty, which should be ignored.
- """
- tx = self.overlay(ID1).construct_signed_transaction(self.peer(ID2), 300)
- tx.signature_a = b"invalid"
- self.database(ID1).BandwidthTransaction.insert(tx)
- cache = self.add_cache(ID1, BandwidthTransactionSignCache(self.overlay(ID1), tx))
- self.overlay(ID1).send_transaction(tx, self.address(ID2), cache.number)
-
- await self.deliver_messages()
-
- assert self.database(ID2).get_total_taken(self.key_bin(ID1)) == 0
-
- async def test_ignore_unknown_transaction(self):
- """
- Test whether we are ignoring a transaction that is not in our cache.
- """
- tx = BandwidthTransactionData(ID2, self.key_bin(ID1), self.key_bin(ID2), EMPTY_SIGNATURE, EMPTY_SIGNATURE, 1000)
- tx.sign(self.private_key(ID1), as_a=True)
- self.overlay(ID1).send_transaction(tx, self.address(ID2), 1234)
-
- await self.deliver_messages()
-
- assert not self.database(ID1).get_latest_transaction(self.key_bin(ID1), self.key_bin(ID2))
-
- 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.
- """
- tx1 = BandwidthTransactionData(1, self.key_bin(ID1), self.key_bin(ID2), EMPTY_SIGNATURE, EMPTY_SIGNATURE, 1000)
- tx2 = BandwidthTransactionData(2, self.key_bin(ID1), self.key_bin(ID2), EMPTY_SIGNATURE, EMPTY_SIGNATURE, 2000)
-
- # Send them in reverse order
- cache = self.add_cache(ID1, BandwidthTransactionSignCache(self.overlay(ID1), tx1))
- self.overlay(ID1).send_transaction(tx2, self.address(ID2), cache.number)
- await self.deliver_messages()
-
- # This one should be ignored by node 1
- cache = self.add_cache(ID1, BandwidthTransactionSignCache(self.overlay(ID1), tx1))
- self.overlay(ID1).send_transaction(tx1, self.address(ID2), cache.number)
- await self.deliver_messages()
-
- # Both parties should have the transaction with amount 2000 in their database
- assert self.database(ID1).get_total_taken(self.key_bin(ID1)) == 2000
- assert self.database(ID2).get_total_taken(self.key_bin(ID1)) == 2000
-
- async def test_querying_peer(self):
- """
- Test whether node C can query node B to get the transaction between A and B.
- """
- await self.overlay(ID1).do_payout(self.peer(ID2), 500)
-
- self.add_node_to_experiment(self.create_node())
- self.overlay(ID3).query_transactions(self.peer(ID2))
-
- await self.deliver_messages()
-
- assert self.database(ID3).get_total_taken(self.key_bin(ID1)) == 500
-
- async def test_query_random_peer(self):
- """
- Test whether node C can query node B to get the transaction between A and B.
- """
- await self.overlay(ID1).do_payout(self.peer(ID2), 500)
-
- self.add_node_to_experiment(self.create_node())
- self.overlay(ID3).query_random_peer()
-
- await self.deliver_messages()
-
- assert self.database(ID3).get_total_taken(self.key_bin(ID1)) == 500
diff --git a/src/tribler/core/components/bandwidth_accounting/tests/test_database.py b/src/tribler/core/components/bandwidth_accounting/tests/test_database.py
deleted file mode 100644
index 5026b58f5a5..00000000000
--- a/src/tribler/core/components/bandwidth_accounting/tests/test_database.py
+++ /dev/null
@@ -1,168 +0,0 @@
-import random
-
-import pytest
-from ipv8.keyvault.crypto import default_eccrypto
-from pony.orm import db_session
-
-from tribler.core.components.bandwidth_accounting.db.database import BandwidthDatabase
-from tribler.core.components.bandwidth_accounting.db.transaction import BandwidthTransactionData, EMPTY_SIGNATURE
-from tribler.core.utilities.utilities import MEMORY_DB
-
-
-@pytest.fixture
-def my_key():
- return default_eccrypto.generate_key('curve25519')
-
-
-@pytest.fixture
-def bandwidth_db(tmpdir, my_key):
- db = BandwidthDatabase(MEMORY_DB, my_key.pub().key_to_bin())
- yield db
- db.shutdown()
-
-
-@db_session
-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)
-
-
-@db_session
-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
-
-
-@db_session
-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
-
-
-@db_session
-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)
-
-
-@db_session
-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
-
-
-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
-
-
-@db_session
-def test_peers_helped(bandwidth_db):
- assert bandwidth_db.get_num_peers_helped(b"a") == 0
- tx1 = BandwidthTransactionData(1, b"a", b"b", EMPTY_SIGNATURE, EMPTY_SIGNATURE, 3000)
- bandwidth_db.BandwidthTransaction.insert(tx1)
- assert bandwidth_db.get_num_peers_helped(b"a") == 1
- tx2 = BandwidthTransactionData(2, b"a", b"c", EMPTY_SIGNATURE, EMPTY_SIGNATURE, 3000)
- bandwidth_db.BandwidthTransaction.insert(tx2)
- assert bandwidth_db.get_num_peers_helped(b"a") == 2
- tx3 = BandwidthTransactionData(1, b"b", b"c", EMPTY_SIGNATURE, EMPTY_SIGNATURE, 3000)
- bandwidth_db.BandwidthTransaction.insert(tx3)
- assert bandwidth_db.get_num_peers_helped(b"a") == 2
-
-
-@db_session
-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
-
-
-@db_session
-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
diff --git a/src/tribler/core/components/bandwidth_accounting/tests/test_transaction.py b/src/tribler/core/components/bandwidth_accounting/tests/test_transaction.py
deleted file mode 100644
index 43af80b07db..00000000000
--- a/src/tribler/core/components/bandwidth_accounting/tests/test_transaction.py
+++ /dev/null
@@ -1,41 +0,0 @@
-from ipv8.keyvault.crypto import default_eccrypto
-
-from tribler.core.components.bandwidth_accounting.db.transaction import BandwidthTransactionData, EMPTY_SIGNATURE
-
-
-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
-
-
-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()
diff --git a/src/tribler/core/components/payout/__init__.py b/src/tribler/core/components/payout/__init__.py
deleted file mode 100644
index e69de29bb2d..00000000000
diff --git a/src/tribler/core/components/payout/payout_component.py b/src/tribler/core/components/payout/payout_component.py
deleted file mode 100644
index 4a6ceee29f6..00000000000
--- a/src/tribler/core/components/payout/payout_component.py
+++ /dev/null
@@ -1,38 +0,0 @@
-from tribler.core import notifications
-from tribler.core.components.bandwidth_accounting.bandwidth_accounting_component import BandwidthAccountingComponent
-from tribler.core.components.component import Component
-from tribler.core.components.ipv8.ipv8_component import Ipv8Component
-from tribler.core.components.payout.payout_manager import PayoutManager
-from tribler.core.components.reporter.reporter_component import ReporterComponent
-
-INFINITE = -1
-
-
-class PayoutComponent(Component):
- payout_manager: PayoutManager = None
-
- async def run(self):
- await super().run()
-
- config = self.session.config
- assert not config.gui_test_mode
-
- await self.get_component(ReporterComponent)
-
- ipv8_component = await self.require_component(Ipv8Component)
- bandwidth_accounting_component = await self.require_component(BandwidthAccountingComponent)
-
- self.payout_manager = PayoutManager(bandwidth_accounting_component.community,
- ipv8_component.dht_discovery_community)
-
- self.session.notifier.add_observer(notifications.peer_disconnected, self.payout_manager.on_peer_disconnected)
- self.session.notifier.add_observer(notifications.tribler_torrent_peer_update, self.payout_manager.update_peer)
-
- async def shutdown(self):
- await super().shutdown()
- if self.payout_manager:
- notifier = self.session.notifier
- notifier.remove_observer(notifications.peer_disconnected, self.payout_manager.on_peer_disconnected)
- notifier.remove_observer(notifications.tribler_torrent_peer_update, self.payout_manager.update_peer)
-
- await self.payout_manager.shutdown()
diff --git a/src/tribler/core/components/payout/payout_manager.py b/src/tribler/core/components/payout/payout_manager.py
deleted file mode 100644
index 44cb32ba3e7..00000000000
--- a/src/tribler/core/components/payout/payout_manager.py
+++ /dev/null
@@ -1,68 +0,0 @@
-import logging
-
-from ipv8.taskmanager import TaskManager, task
-
-from tribler.core.utilities.unicode import hexlify
-
-
-class PayoutManager(TaskManager):
- """
- This manager is responsible for keeping track of known Tribler peers and doing (zero-hop) payouts.
- """
-
- def __init__(self, bandwidth_community, dht):
- super().__init__()
- self.logger = logging.getLogger(self.__class__.__name__)
- self.bandwidth_community = bandwidth_community
- self.dht = dht
- self.tribler_peers = {}
-
- def on_peer_disconnected(self, peer_id: bytes):
- # do_payout is not specified directly, as PyCharm does not understand its type correctly due to a task decorator
- self.do_payout(peer_id)
-
- @task
- async def do_payout(self, peer_id: bytes):
- """
- Perform a payout to a given mid. First, determine the outstanding balance. Then resolve the node in the DHT.
- """
- if peer_id not in self.tribler_peers:
- return None
-
- total_bytes = sum(self.tribler_peers[peer_id].values())
-
- self.logger.info("Doing direct payout to %s (%d bytes)", hexlify(peer_id), total_bytes)
- try:
- nodes = await self.dht.connect_peer(peer_id)
- except Exception as e:
- self.logger.warning("Error while doing DHT lookup for payouts, error %s", e)
- return None
-
- self.logger.debug("Received %d nodes for DHT lookup", len(nodes))
- if not nodes:
- return None
-
- try:
- await self.bandwidth_community.do_payout(nodes[0], total_bytes)
- except Exception as e:
- self.logger.error("Error while doing bandwidth payout, error %s", e)
- return None
-
- # Remove the outstanding bytes; otherwise we will payout again
- self.tribler_peers.pop(peer_id, None)
- return nodes[0]
-
- def update_peer(self, peer_id: bytes, infohash: bytes, balance: int):
- """
- Update a peer with a specific mid for a specific infohash.
- """
- self.logger.debug("Updating peer with mid %s and ih %s (balance: %d)", hexlify(peer_id),
- hexlify(infohash), balance)
-
- if peer_id not in self.tribler_peers:
- self.tribler_peers[peer_id] = {}
-
- self.tribler_peers[peer_id][infohash] = balance
-
- async def shutdown(self):
- await self.shutdown_task_manager()
diff --git a/src/tribler/core/components/payout/tests/__init__.py b/src/tribler/core/components/payout/tests/__init__.py
deleted file mode 100644
index e69de29bb2d..00000000000
diff --git a/src/tribler/core/components/payout/tests/test_payout_component.py b/src/tribler/core/components/payout/tests/test_payout_component.py
deleted file mode 100644
index 4786a6355dc..00000000000
--- a/src/tribler/core/components/payout/tests/test_payout_component.py
+++ /dev/null
@@ -1,15 +0,0 @@
-# pylint: disable=protected-access
-
-from tribler.core.components.bandwidth_accounting.bandwidth_accounting_component import BandwidthAccountingComponent
-from tribler.core.components.ipv8.ipv8_component import Ipv8Component
-from tribler.core.components.key.key_component import KeyComponent
-from tribler.core.components.payout.payout_component import PayoutComponent
-from tribler.core.components.session import Session
-
-
-async def test_payout_component(tribler_config):
- components = [BandwidthAccountingComponent(), KeyComponent(), Ipv8Component(), PayoutComponent()]
- async with Session(tribler_config, components) as session:
- comp = session.get_instance(PayoutComponent)
- assert comp.started_event.is_set() and not comp.failed
- assert comp.payout_manager
diff --git a/src/tribler/core/components/payout/tests/test_payout_manager.py b/src/tribler/core/components/payout/tests/test_payout_manager.py
deleted file mode 100644
index aa587128a2f..00000000000
--- a/src/tribler/core/components/payout/tests/test_payout_manager.py
+++ /dev/null
@@ -1,97 +0,0 @@
-from unittest.mock import Mock
-
-import pytest
-from ipv8.util import succeed
-
-from tribler.core.components.payout.payout_manager import PayoutManager
-
-
-@pytest.fixture
-async def payout_manager():
- fake_bw_community = Mock()
-
- fake_response_peer = Mock()
- fake_response_peer.public_key = Mock()
- fake_response_peer.public_key.key_to_bin = lambda: b'a' * 64
- fake_dht = Mock()
- fake_dht.connect_peer = lambda *_: succeed([fake_response_peer])
-
- payout_manager = PayoutManager(fake_bw_community, fake_dht)
- yield payout_manager
- await payout_manager.shutdown()
-
-
-async def test_do_payout(payout_manager):
- """
- Test doing a payout
- """
- res = await payout_manager.do_payout(b'a') # Does not exist
- assert not res
- payout_manager.update_peer(b'b', b'c', 10 * 1024 * 1024)
- payout_manager.update_peer(b'b', b'd', 1337)
-
- def mocked_do_payout(*_, **__):
- return succeed(None)
-
- payout_manager.bandwidth_community.do_payout = mocked_do_payout
- res = await payout_manager.do_payout(b'b')
- assert res
-
-
-async def test_do_payout_dht_error(payout_manager):
- """
- Test whether we are not doing a payout when the DHT lookup fails
- """
-
- def err_connect_peer(_):
- raise RuntimeError("test")
-
- payout_manager.update_peer(b'a', b'b', 10 * 1024 * 1024)
- payout_manager.dht.connect_peer = err_connect_peer
- res = await payout_manager.do_payout(b'a')
- assert not res
-
-
-async def test_do_payout_no_dht_peers(payout_manager):
- """
- Test whether we are not doing a payout when there are no peers returned by the DHT
- """
-
- def connect_peer(_):
- return succeed([])
-
- payout_manager.update_peer(b'a', b'b', 10 * 1024 * 1024)
- payout_manager.dht.connect_peer = connect_peer
- res = await payout_manager.do_payout(b'a')
- assert not res
-
-
-async def test_do_payout_error(payout_manager):
- """
- Test whether we are not doing a payout when the payout fails
- """
-
- def connect_peer(_):
- return succeed([b"abc"])
-
- def do_payout(*_):
- raise RuntimeError("test")
-
- payout_manager.update_peer(b'a', b'b', 10 * 1024 * 1024)
- payout_manager.dht.connect_peer = connect_peer
- payout_manager.bandwidth_community.do_payout = do_payout
- res = await payout_manager.do_payout(b'a')
- assert not res
-
-
-def test_update_peer(payout_manager):
- """
- Test the updating of a specific peer
- """
- payout_manager.update_peer(b'a', b'b', 1337)
- assert b'a' in payout_manager.tribler_peers
- assert b'b' in payout_manager.tribler_peers[b'a']
- assert payout_manager.tribler_peers[b'a'][b'b'] == 1337
-
- payout_manager.update_peer(b'a', b'b', 1338)
- assert payout_manager.tribler_peers[b'a'][b'b'] == 1338
diff --git a/src/tribler/core/components/restapi/rest/tests/test_statistics_endpoint.py b/src/tribler/core/components/restapi/rest/tests/test_statistics_endpoint.py
index a61be19e762..49fa0379c2f 100644
--- a/src/tribler/core/components/restapi/rest/tests/test_statistics_endpoint.py
+++ b/src/tribler/core/components/restapi/rest/tests/test_statistics_endpoint.py
@@ -1,13 +1,12 @@
-from unittest.mock import Mock
+from unittest.mock import MagicMock, Mock
import pytest
-from tribler.core.components.bandwidth_accounting.community.bandwidth_accounting_community \
- import BandwidthAccountingCommunity
-from tribler.core.components.bandwidth_accounting.settings import BandwidthAccountingSettings
from tribler.core.components.ipv8.adapters_tests import TriblerMockIPv8
from tribler.core.components.restapi.rest.base_api_test import do_request
from tribler.core.components.restapi.rest.statistics_endpoint import StatisticsEndpoint
+from tribler.core.components.tunnel.community.tunnel_community import TriblerTunnelCommunity
+from tribler.core.components.tunnel.settings import TunnelCommunitySettings
# pylint: disable=redefined-outer-name
@@ -15,8 +14,12 @@
@pytest.fixture
async def endpoint(metadata_store):
- ipv8 = TriblerMockIPv8("low", BandwidthAccountingCommunity, database=Mock(),
- settings=BandwidthAccountingSettings())
+ ipv8 = TriblerMockIPv8("curve25519",
+ TriblerTunnelCommunity,
+ settings={"max_circuits": 1},
+ config=TunnelCommunitySettings(),
+ socks_servers=MagicMock(),
+ dlmgr=Mock())
ipv8.overlays = [ipv8.overlay]
ipv8.endpoint.bytes_up = 100
ipv8.endpoint.bytes_down = 20
diff --git a/src/tribler/core/components/restapi/restapi_component.py b/src/tribler/core/components/restapi/restapi_component.py
index a43ff2bdf1e..165a586536a 100644
--- a/src/tribler/core/components/restapi/restapi_component.py
+++ b/src/tribler/core/components/restapi/restapi_component.py
@@ -2,8 +2,6 @@
from typing import Type
from ipv8.REST.root_endpoint import RootEndpoint as IPV8RootEndpoint
-from tribler.core.components.bandwidth_accounting.bandwidth_accounting_component import BandwidthAccountingComponent
-from tribler.core.components.bandwidth_accounting.restapi.bandwidth_endpoint import BandwidthEndpoint
from tribler.core.components.component import Component
from tribler.core.components.content_discovery.content_discovery_component import ContentDiscoveryComponent
from tribler.core.components.content_discovery.restapi.search_endpoint import SearchEndpoint
@@ -72,7 +70,6 @@ async def run(self):
ipv8_component = await self.maybe_component(Ipv8Component)
libtorrent_component = await self.maybe_component(LibtorrentComponent)
resource_monitor_component = await self.maybe_component(ResourceMonitorComponent)
- bandwidth_accounting_component = await self.maybe_component(BandwidthAccountingComponent)
content_discovery_component = await self.maybe_component(ContentDiscoveryComponent)
knowledge_component = await self.maybe_component(KnowledgeComponent)
tunnel_component = await self.maybe_component(TunnelsComponent)
@@ -93,7 +90,6 @@ async def run(self):
self.maybe_add(DebugEndpoint, config.state_dir, log_dir, tunnel_community=tunnel_community,
resource_monitor=resource_monitor_component.resource_monitor,
core_exception_handler=self._core_exception_handler)
- self.maybe_add(BandwidthEndpoint, bandwidth_accounting_component.community)
self.maybe_add(DownloadsEndpoint, libtorrent_component.download_manager,
metadata_store=db_component.mds, tunnel_community=tunnel_community)
self.maybe_add(CreateTorrentEndpoint, libtorrent_component.download_manager)
diff --git a/src/tribler/core/components/restapi/tests/test_restapi_component.py b/src/tribler/core/components/restapi/tests/test_restapi_component.py
index 21991bdcc94..7e02178c4b5 100644
--- a/src/tribler/core/components/restapi/tests/test_restapi_component.py
+++ b/src/tribler/core/components/restapi/tests/test_restapi_component.py
@@ -2,7 +2,6 @@
import pytest
-from tribler.core.components.bandwidth_accounting.bandwidth_accounting_component import BandwidthAccountingComponent
from tribler.core.components.database.database_component import DatabaseComponent
from tribler.core.components.exceptions import NoneComponent
from tribler.core.components.ipv8.ipv8_component import Ipv8Component
@@ -20,7 +19,7 @@
# pylint: disable=protected-access, not-callable, redefined-outer-name
async def test_rest_component(tribler_config):
components = [KeyComponent(), RESTComponent(), Ipv8Component(), LibtorrentComponent(), ResourceMonitorComponent(),
- BandwidthAccountingComponent(), KnowledgeComponent(), SocksServersComponent(), DatabaseComponent()]
+ KnowledgeComponent(), SocksServersComponent(), DatabaseComponent()]
async with Session(tribler_config, components) as session:
# Test REST component starts normally
comp = session.get_instance(RESTComponent)
diff --git a/src/tribler/core/components/tunnel/community/caches.py b/src/tribler/core/components/tunnel/community/caches.py
index 49aa437cec2..569f9d14589 100644
--- a/src/tribler/core/components/tunnel/community/caches.py
+++ b/src/tribler/core/components/tunnel/community/caches.py
@@ -1,18 +1,6 @@
from asyncio import Future
-from ipv8.requestcache import NumberCache, RandomNumberCache
-
-
-class BalanceRequestCache(NumberCache):
-
- def __init__(self, community, circuit_id, balance_future):
- super().__init__(community.request_cache, "balance-request", circuit_id)
- self.circuit_id = circuit_id
- self.balance_future = balance_future
- self.register_future(self.balance_future)
-
- def on_timeout(self):
- pass
+from ipv8.requestcache import RandomNumberCache
class HTTPRequestCache(RandomNumberCache):
diff --git a/src/tribler/core/components/tunnel/community/payload.py b/src/tribler/core/components/tunnel/community/payload.py
index 774be62ac8d..df97f89742b 100644
--- a/src/tribler/core/components/tunnel/community/payload.py
+++ b/src/tribler/core/components/tunnel/community/payload.py
@@ -3,65 +3,6 @@
from ipv8.messaging.lazy_payload import VariablePayload, vp_compile
-@vp_compile
-class BandwidthTransactionPayload(VariablePayload):
- """
- Payload for a message containing a bandwidth transaction.
- """
- msg_id = 30
- format_list = ['I', '74s', '74s', '64s', '64s', 'Q', 'Q', 'I', 'I']
- names = ["sequence_number", "public_key_a", "public_key_b", "signature_a", "signature_b", "amount", "timestamp",
- "circuit_id", "base_amount"]
-
- @classmethod
- def from_transaction(cls, transaction, circuit_id: int, base_amount: int):
- """
- Create a transaction from the provided payload.
- :param transaction: The BandwidthTransaction to convert to a payload.
- :param circuit_id: The circuit identifier to include in the payload.
- :param base_amount: The base amount of bandwidth to payout.
- """
- return BandwidthTransactionPayload(
- transaction.sequence_number,
- transaction.public_key_a,
- transaction.public_key_b,
- transaction.signature_a,
- transaction.signature_b,
- transaction.amount,
- transaction.timestamp,
- circuit_id,
- base_amount
- )
-
-
-@vp_compile
-class BalanceResponsePayload(VariablePayload):
- """
- Payload that contains the bandwidth balance of a specific peer.
- """
- msg_id = 31
- format_list = ["I", "q"]
- names = ["circuit_id", "balance"]
-
-
-class RelayBalanceResponsePayload(BalanceResponsePayload):
- msg_id = 32
-
-
-@vp_compile
-class BalanceRequestPayload(VariablePayload):
- msg_id = 33
- format_list = ['I', 'H']
- names = ['circuit_id', 'identifier']
-
-
-@vp_compile
-class RelayBalanceRequestPayload(VariablePayload):
- msg_id = 34
- format_list = ['I']
- names = ['circuit_id']
-
-
@vp_compile
class HTTPRequestPayload(VariablePayload):
msg_id = 28
diff --git a/src/tribler/core/components/tunnel/community/tunnel_community.py b/src/tribler/core/components/tunnel/community/tunnel_community.py
index 37316b62f70..bb2d387690d 100644
--- a/src/tribler/core/components/tunnel/community/tunnel_community.py
+++ b/src/tribler/core/components/tunnel/community/tunnel_community.py
@@ -1,52 +1,36 @@
import hashlib
import math
-import sys
import time
-from asyncio import Future, TimeoutError as AsyncTimeoutError, open_connection
+from asyncio import TimeoutError as AsyncTimeoutError, open_connection
from binascii import unhexlify
from collections import Counter
from distutils.version import LooseVersion
from typing import Callable, List, Optional
import async_timeout
-from ipv8.messaging.anonymization.caches import CreateRequestCache
from ipv8.messaging.anonymization.community import unpack_cell
from ipv8.messaging.anonymization.hidden_services import HiddenTunnelCommunity
-from ipv8.messaging.anonymization.payload import EstablishIntroPayload, NO_CRYPTO_PACKETS
+from ipv8.messaging.anonymization.payload import EstablishIntroPayload
from ipv8.messaging.anonymization.tunnel import (
- CIRCUIT_STATE_CLOSING,
CIRCUIT_STATE_READY,
- CIRCUIT_TYPE_DATA,
CIRCUIT_TYPE_IP_SEEDER,
- CIRCUIT_TYPE_RP_DOWNLOADER,
CIRCUIT_TYPE_RP_SEEDER,
- EXIT_NODE,
PEER_FLAG_EXIT_BT,
PEER_FLAG_EXIT_IPV8,
- RelayRoute,
)
-from ipv8.peer import Peer
from ipv8.peerdiscovery.network import Network
from ipv8.taskmanager import task
-from ipv8.types import Address
from ipv8.util import succeed
-from pony.orm import OrmError
from tribler.core import notifications
-from tribler.core.components.bandwidth_accounting.db.transaction import BandwidthTransactionData
from tribler.core.components.ipv8.tribler_community import args_kwargs_to_community_settings
from tribler.core.components.socks_servers.socks5.server import Socks5Server
-from tribler.core.components.tunnel.community.caches import BalanceRequestCache, HTTPRequestCache
+from tribler.core.components.tunnel.community.caches import HTTPRequestCache
from tribler.core.components.tunnel.community.discovery import GoldenRatioStrategy
from tribler.core.components.tunnel.community.dispatcher import TunnelDispatcher
from tribler.core.components.tunnel.community.payload import (
- BalanceRequestPayload,
- BalanceResponsePayload,
- BandwidthTransactionPayload,
HTTPRequestPayload,
HTTPResponsePayload,
- RelayBalanceRequestPayload,
- RelayBalanceResponsePayload,
)
from tribler.core.utilities.bencodecheck import is_bencoded
from tribler.core.utilities.path_util import Path
@@ -65,18 +49,16 @@
class TriblerTunnelCommunity(HiddenTunnelCommunity):
"""
This community is built upon the anonymous messaging layer in IPv8.
- It adds support for libtorrent anonymous downloads and bandwidth token payout when closing circuits.
+ It adds support for libtorrent anonymous downloads.
"""
community_id = unhexlify('a3591a6bd89bbaca0974062a1287afcfbc6fd6bb')
def __init__(self, *args, **kwargs):
- self.bandwidth_community = kwargs.pop('bandwidth_community', None)
self.exitnode_cache: Optional[Path] = kwargs.pop('exitnode_cache', None)
self.config = kwargs.pop('config', None)
self.notifier = kwargs.pop('notifier', None)
self.download_manager = kwargs.pop('dlmgr', None)
self.socks_servers: List[Socks5Server] = kwargs.pop('socks_servers', [])
- num_competing_slots = self.config.competing_slots
num_random_slots = self.config.random_slots
super().__init__(args_kwargs_to_community_settings(self.settings_class, args, kwargs))
@@ -90,7 +72,6 @@ def __init__(self, *args, **kwargs):
self.bittorrent_peers = {}
self.dispatcher = TunnelDispatcher(self)
self.download_states = {}
- self.competing_slots = [(0, None)] * num_competing_slots # 1st tuple item = token balance, 2nd = circuit id
self.random_slots = [None] * num_random_slots
# This callback is invoked with a tuple (time, balance) when we reject a circuit
self.reject_callback: Optional[Callable] = None
@@ -101,17 +82,9 @@ def __init__(self, *args, **kwargs):
for server in self.socks_servers:
server.output_stream = self.dispatcher
- self.add_message_handler(BandwidthTransactionPayload, self.on_payout)
-
- self.add_cell_handler(BalanceRequestPayload, self.on_balance_request_cell)
- self.add_cell_handler(RelayBalanceRequestPayload, self.on_relay_balance_request_cell)
- self.add_cell_handler(BalanceResponsePayload, self.on_balance_response_cell)
- self.add_cell_handler(RelayBalanceResponsePayload, self.on_relay_balance_response_cell)
self.add_cell_handler(HTTPRequestPayload, self.on_http_request)
self.add_cell_handler(HTTPResponsePayload, self.on_http_response)
- NO_CRYPTO_PACKETS.extend([BalanceRequestPayload.msg_id, BalanceResponsePayload.msg_id])
-
if self.exitnode_cache is not None:
self.restore_exitnodes_from_disk()
if self.download_manager is not None:
@@ -163,130 +136,23 @@ def restore_exitnodes_from_disk(self):
else:
self.logger.warning('Could not retrieve backup exitnode cache, file does not exist!')
- def on_token_balance(self, circuit_id, balance):
- """
- We received the token balance of a circuit initiator. Check whether we can allocate a slot to this user.
- """
- if not self.request_cache.has("balance-request", circuit_id):
- self.logger.warning("Received token balance without associated request cache!")
- return
-
- cache = self.request_cache.pop("balance-request", circuit_id)
-
- lowest_balance = sys.maxsize
- lowest_index = -1
- for ind, tup in enumerate(self.competing_slots):
- if not tup[1]:
- # The slot is empty, take it
- self.competing_slots[ind] = (balance, circuit_id)
- cache.balance_future.set_result(True)
- return
-
- if tup[0] < lowest_balance:
- lowest_balance = tup[0]
- lowest_index = ind
-
- if balance > lowest_balance:
- # We kick this user out
- old_circuit_id = self.competing_slots[lowest_index][1]
- self.logger.info("Kicked out circuit %s (balance: %s) in favor of %s (balance: %s)",
- old_circuit_id, lowest_balance, circuit_id, balance)
- self.competing_slots[lowest_index] = (balance, circuit_id)
-
- self.remove_relay(old_circuit_id, destroy=DESTROY_REASON_BALANCE)
- self.remove_exit_socket(old_circuit_id, destroy=DESTROY_REASON_BALANCE)
-
- cache.balance_future.set_result(True)
- else:
- # We can't compete with the balances in the existing slots
- if self.reject_callback:
- self.reject_callback(time.time(), balance)
- cache.balance_future.set_result(False)
-
def should_join_circuit(self, create_payload, previous_node_address):
"""
Check whether we should join a circuit. Returns a future that fires with a boolean.
"""
- if self.settings.max_joined_circuits <= len(self.relay_from_to) + len(self.exit_sockets):
- self.logger.warning("too many relays (%d)", (len(self.relay_from_to) + len(self.exit_sockets)))
+ joined_circuits = len(self.relay_from_to) + len(self.exit_sockets)
+ if self.settings.max_joined_circuits <= joined_circuits:
+ self.logger.warning("too many relays (%d)", joined_circuits)
return succeed(False)
circuit_id = create_payload.circuit_id
- if self.request_cache.has('balance-request', circuit_id):
- self.logger.warning("balance request already in progress for circuit %d", circuit_id)
- return succeed(False)
# Check whether we have a random open slot, if so, allocate this to this request.
for index, slot in enumerate(self.random_slots):
if not slot:
self.random_slots[index] = circuit_id
return succeed(True)
-
- # No random slots but this user might be allocated a competing slot.
- # Next, we request the token balance of the circuit initiator.
- self.logger.info("Requesting balance of circuit initiator!")
- balance_future = Future()
- self.request_cache.add(BalanceRequestCache(self, circuit_id, balance_future))
-
- # Temporarily add these values, otherwise we are unable to communicate with the previous hop.
- self.directions[circuit_id] = EXIT_NODE
- shared_secret, _, _ = self.crypto.generate_diffie_shared_secret(create_payload.key)
- self.relay_session_keys[circuit_id] = self.crypto.generate_session_keys(shared_secret)
-
- self.send_cell(Peer(create_payload.node_public_key, previous_node_address),
- BalanceRequestPayload(circuit_id, create_payload.identifier))
-
- self.directions.pop(circuit_id, None)
- self.relay_session_keys.pop(circuit_id, None)
-
- return balance_future
-
- @unpack_cell(BalanceRequestPayload)
- def on_balance_request_cell(self, _, payload, __):
- if self.request_cache.has("create", payload.identifier):
- request = self.request_cache.get("create", payload.identifier)
- forwarding_relay = RelayRoute(request.from_circuit_id, request.peer)
- self.send_cell(forwarding_relay.peer, RelayBalanceRequestPayload(forwarding_relay.circuit_id))
- elif self.request_cache.has("retry", payload.circuit_id):
- self.on_balance_request(payload)
- else:
- self.logger.warning("Circuit creation cache for id %s not found!", payload.circuit_id)
-
- @unpack_cell(RelayBalanceRequestPayload)
- def on_relay_balance_request_cell(self, source_address, payload, _):
- self.on_balance_request(payload)
-
- def on_balance_request(self, payload):
- """
- We received a balance request from a relay or exit node. Respond with the latest block in our chain.
- """
- if not self.bandwidth_community:
- self.logger.warning("Bandwidth community is not available, unable to send a balance response!")
- return
-
- # Get the latest block
-
- # Get the current balance and send it back
- balance = self.bandwidth_community.database.get_balance(self.my_peer.public_key.key_to_bin())
-
- # We either send the response directly or relay the response to the last verified hop
- circuit = self.circuits[payload.circuit_id]
- if not circuit.hops:
- self.send_cell(circuit.peer, BalanceResponsePayload(circuit.circuit_id, balance))
- else:
- self.send_cell(circuit.peer, RelayBalanceResponsePayload(circuit.circuit_id, balance))
-
- @unpack_cell(BalanceResponsePayload)
- def on_balance_response_cell(self, source_address, payload, _):
- self.on_token_balance(payload.circuit_id, payload.balance)
-
- @unpack_cell(RelayBalanceResponsePayload)
- def on_relay_balance_response_cell(self, source_address, payload, _):
- # At this point, we don't have the circuit ID of the follow-up hop. We have to iterate over the items in the
- # request cache and find the link to the next hop.
- for cache in self.request_cache._identifiers.values():
- if isinstance(cache, CreateRequestCache) and cache.from_circuit_id == payload.circuit_id:
- self.send_cell(cache.to_peer, BalanceResponsePayload(cache.to_circuit_id, payload.balance))
+ return succeed(False)
def readd_bittorrent_peers(self):
for torrent, peers in list(self.bittorrent_peers.items()):
@@ -311,66 +177,6 @@ def update_torrent(self, peers, download):
if self.find_circuits():
self.readd_bittorrent_peers()
- def do_payout(self, peer: Peer, circuit_id: int, amount: int, base_amount: int) -> None:
- """
- Perform a payout to a specific peer.
- :param peer: The peer to perform the payout to, usually the next node in the circuit.
- :param circuit_id: The circuit id of the payout, used by the subsequent node.
- :param amount: The amount to put in the transaction, multiplier of base_amount.
- :param base_amount: The base amount for the payout.
- """
- self.logger.info("Sending payout of %d (base: %d) to %s (cid: %s)", amount, base_amount, peer, circuit_id)
-
- tx = self.bandwidth_community.construct_signed_transaction(peer, amount)
- try:
- self.bandwidth_community.database.BandwidthTransaction.insert(tx)
- except OrmError as e:
- self.logger.exception(e)
- return
-
- payload = BandwidthTransactionPayload.from_transaction(tx, circuit_id, base_amount)
- packet = self._ez_pack(self._prefix, 30, [payload], False)
- self.send_packet(peer, packet)
-
- 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)
-
def clean_from_slots(self, circuit_id):
"""
Clean a specific circuit from the allocated slots.
@@ -379,10 +185,6 @@ def clean_from_slots(self, circuit_id):
if slot == circuit_id:
self.random_slots[ind] = None
- for ind, tup in enumerate(self.competing_slots):
- if tup[1] == circuit_id:
- self.competing_slots[ind] = (0, None)
-
def remove_circuit(self, circuit_id, additional_info='', remove_now=False, destroy=False):
if circuit_id not in self.circuits:
self.logger.warning("Circuit %d not found when trying to remove it", circuit_id)
@@ -394,22 +196,6 @@ def remove_circuit(self, circuit_id, additional_info='', remove_now=False, destr
if self.notifier:
self.notifier[notifications.circuit_removed](circuit, additional_info)
- # Ignore circuits that are closing so we do not payout again if we receive a destroy message.
- if circuit.state != CIRCUIT_STATE_CLOSING and self.bandwidth_community:
-
- # We should perform a payout of the removed circuit.
- if circuit.ctype == CIRCUIT_TYPE_RP_DOWNLOADER:
- # We remove an e2e circuit as downloader. We pay the subsequent nodes in the downloader part of the e2e
- # circuit. In addition, we pay for one hop seeder anonymity since we don't know the circuit length at
- # the seeder side.
- self.do_payout(circuit.peer, circuit_id, circuit.bytes_down * ((circuit.goal_hops * 2) + 1),
- circuit.bytes_down)
-
- if circuit.ctype == CIRCUIT_TYPE_DATA:
- # We remove a regular data circuit as downloader. Pay the relay nodes and the exit nodes.
- self.do_payout(circuit.peer, circuit_id, circuit.bytes_down * (circuit.goal_hops * 2 - 1),
- circuit.bytes_down)
-
affected_peers = self.dispatcher.circuit_dead(circuit)
# Make sure the circuit is marked as closing, otherwise we may end up reusing it
diff --git a/src/tribler/core/components/tunnel/settings.py b/src/tribler/core/components/tunnel/settings.py
index 92ee8b86610..bda267fbd88 100644
--- a/src/tribler/core/components/tunnel/settings.py
+++ b/src/tribler/core/components/tunnel/settings.py
@@ -6,8 +6,7 @@
class TunnelCommunitySettings(TriblerConfigSection):
enabled: bool = True
exitnode_enabled: bool = False
- random_slots: int = 5
- competing_slots: int = 15
+ random_slots: int = 20
testnet: bool = Field(default=False, env='TUNNEL_TESTNET')
min_circuits: int = 3
max_circuits: int = 10
diff --git a/src/tribler/core/components/tunnel/tests/test_triblertunnel_community.py b/src/tribler/core/components/tunnel/tests/test_triblertunnel_community.py
index d9df2cd1517..ffd905103fc 100644
--- a/src/tribler/core/components/tunnel/tests/test_triblertunnel_community.py
+++ b/src/tribler/core/components/tunnel/tests/test_triblertunnel_community.py
@@ -1,13 +1,12 @@
from __future__ import annotations
import os
-from asyncio import Future, TimeoutError as AsyncTimeoutError, sleep, wait_for
+from asyncio import TimeoutError as AsyncTimeoutError, wait_for
from collections import defaultdict
from random import random
from unittest.mock import Mock
import pytest
-
from ipv8.keyvault.public.libnaclkey import LibNaCLPK
from ipv8.messaging.anonymization.payload import EstablishIntroPayload
from ipv8.messaging.anonymization.tunnel import (
@@ -24,13 +23,7 @@
from ipv8.test.mocking.exit_socket import MockTunnelExitSocket
from ipv8.util import succeed
-from tribler.core.components.bandwidth_accounting.community.bandwidth_accounting_community import (
- BandwidthAccountingCommunity,
-)
-from tribler.core.components.bandwidth_accounting.db.database import BandwidthDatabase
-from tribler.core.components.bandwidth_accounting.settings import BandwidthAccountingSettings
from tribler.core.components.ipv8.adapters_tests import TriblerMockIPv8
-from tribler.core.components.tunnel.community.payload import BandwidthTransactionPayload
from tribler.core.components.tunnel.community.tunnel_community import PEER_FLAG_EXIT_HTTP, TriblerTunnelCommunity
from tribler.core.components.tunnel.settings import TunnelCommunitySettings
from tribler.core.tests.tools.base_test import MockObject
@@ -38,7 +31,6 @@
from tribler.core.utilities.network_utils import NetworkUtils
from tribler.core.utilities.path_util import Path
from tribler.core.utilities.simpledefs import DownloadStatus
-from tribler.core.utilities.utilities import MEMORY_DB
@pytest.mark.usefixtures("tmp_path")
@@ -54,8 +46,6 @@ def setUp(self):
async def tearDown(self):
test_community.global_dht_services = defaultdict(list) # Reset the global_dht_services variable
- for node in self.nodes:
- await node.overlay.bandwidth_community.unload()
await super().tearDown()
def create_node(self, *args, **kwargs):
@@ -67,12 +57,6 @@ def create_node(self, *args, **kwargs):
)
mock_ipv8.overlay.settings.max_circuits = 1
- db = BandwidthDatabase(db_path=MEMORY_DB, my_pub_key=mock_ipv8.my_peer.public_key.key_to_bin())
-
- # Load the bandwidth accounting community
- mock_ipv8.overlay.bandwidth_community = BandwidthAccountingCommunity(
- mock_ipv8.my_peer, mock_ipv8.endpoint, mock_ipv8.network,
- settings=BandwidthAccountingSettings(), database=db)
mock_ipv8.overlay.dht_provider = MockDHTProvider(Peer(mock_ipv8.overlay.my_peer.key,
mock_ipv8.overlay.my_estimated_wan))
@@ -311,64 +295,6 @@ def test_update_torrent(self):
self.nodes[0].overlay.bittorrent_peers[mock_download] = {('4.4.4.4', 4)}
self.nodes[0].overlay.update_torrent(peers, mock_download)
- async def test_payouts(self):
- """
- Test whether nodes are correctly paid after transferring data
- """
- self.add_node_to_experiment(self.create_node())
- self.add_node_to_experiment(self.create_node())
-
- # Make sure that every node has some initial transactions. This will help us to detect bugs in the
- # relay payout logic, e.g. https://github.com/Tribler/tribler/issues/5789.
- for node in self.nodes:
- for other_node in self.nodes:
- if node == other_node:
- continue
-
- await node.overlay.bandwidth_community.do_payout(other_node.my_peer, 100 * 1024 * 1024)
-
- # Build a tunnel
- self.nodes[2].overlay.settings.peer_flags.add(PEER_FLAG_EXIT_BT)
- await self.introduce_nodes()
- self.nodes[0].overlay.build_tunnels(2)
- await self.deliver_messages(timeout=.5)
-
- self.assertEqual(self.nodes[0].overlay.tunnels_ready(2), 1.0)
-
- # Destroy the circuit
- for circuit_id, circuit in list(self.nodes[0].overlay.circuits.items()):
- circuit.bytes_down = 250 * 1024 * 1024
- await self.nodes[0].overlay.remove_circuit(circuit_id, destroy=1)
- await self.deliver_messages()
-
- # Verify whether the downloader (node 0) correctly paid the relay and exit nodes.
- self.assertTrue(self.nodes[0].overlay.bandwidth_community.database.get_my_balance() < 0)
- self.assertTrue(self.nodes[1].overlay.bandwidth_community.database.get_my_balance() > 0)
- self.assertTrue(self.nodes[2].overlay.bandwidth_community.database.get_my_balance() > 0)
-
- balances = []
- for node_nr in [0, 1, 2]:
- balances.append(self.nodes[node_nr].overlay.bandwidth_community.database.get_my_balance())
-
- balances.sort()
- self.assertEqual(balances[0], -750 * 1024 * 1024)
- self.assertEqual(balances[1], 250 * 1024 * 1024)
- self.assertEqual(balances[2], 500 * 1024 * 1024)
-
- async def test_invalid_payout(self):
- """
- Test whether an invalid payout to another peer is ignored
- """
- self.add_node_to_experiment(self.create_node())
-
- tx = self.nodes[0].overlay.bandwidth_community.construct_signed_transaction(self.nodes[1].my_peer, 1024 * 1024)
- tx.signature_a = b"a" * 32
- payload = BandwidthTransactionPayload.from_transaction(tx, 0, 1024)
- packet = self.nodes[0].overlay._ez_pack(self.nodes[0].overlay._prefix, 30, [payload], False)
- self.nodes[0].overlay.send_packet(self.nodes[1].my_peer, packet)
-
- assert not self.nodes[1].overlay.bandwidth_community.database.get_my_balance()
-
async def test_circuit_reject_too_many(self):
"""
Test whether a circuit is rejected by an exit node if it already joined the max number of circuits
@@ -382,155 +308,6 @@ async def test_circuit_reject_too_many(self):
self.assertEqual(self.nodes[0].overlay.tunnels_ready(1), 0.0)
- async def test_payouts_e2e(self):
- """
- Check if payouts work for an e2e-linked circuit
- """
- self.add_node_to_experiment(self.create_node())
- self.add_node_to_experiment(self.create_node())
-
- service = b'0' * 20
-
- self.nodes[0].overlay.join_swarm(service, 1, seeding=False)
-
- await self.introduce_nodes()
- await self.create_intro(2, service)
- await self.assign_exit_node(0)
-
- await self.nodes[0].overlay.do_peer_discovery()
-
- await self.deliver_messages(timeout=0.5)
-
- # Destroy the e2e-circuit
- removed_circuits = []
- for circuit_id, circuit in self.nodes[0].overlay.circuits.items():
- if circuit.ctype == CIRCUIT_TYPE_RP_DOWNLOADER:
- circuit.bytes_down = 250 * 1024 * 1024
- self.nodes[0].overlay.remove_circuit(circuit_id, destroy=1)
- removed_circuits.append(circuit_id)
-
- await sleep(0.5)
-
- # Verify whether the downloader (node 0) correctly paid the subsequent nodes.
- self.assertTrue(self.nodes[0].overlay.bandwidth_community.database.get_my_balance() < 0)
- self.assertTrue(self.nodes[1].overlay.bandwidth_community.database.get_my_balance() >= 0)
- self.assertTrue(self.nodes[2].overlay.bandwidth_community.database.get_my_balance() > 0)
-
- # Ensure balances remain unchanged after calling remove_circuit a second time
- balances = [self.nodes[i].overlay.bandwidth_community.database.get_my_balance() for i in range(3)]
- for circuit_id in removed_circuits:
- self.nodes[0].overlay.remove_circuit(circuit_id, destroy=1)
- for i in range(3):
- self.assertEqual(self.nodes[i].overlay.bandwidth_community.database.get_my_balance(), balances[i])
-
- async def test_decline_competing_slot(self):
- """
- Test whether a circuit is not created when a node does not have enough balance for a competing slot
- """
- self.add_node_to_experiment(self.create_node())
- self.nodes[1].overlay.settings.peer_flags.add(PEER_FLAG_EXIT_BT)
- await self.introduce_nodes()
- self.nodes[1].overlay.random_slots = []
- self.nodes[1].overlay.competing_slots = [(1000, 1234)]
- self.nodes[0].overlay.build_tunnels(1)
- await self.deliver_messages()
-
- # Assert whether we didn't create the circuit
- self.assertEqual(self.nodes[0].overlay.tunnels_ready(1), 0.0)
-
- async def test_win_competing_slot(self):
- """
- Test whether a circuit is created when a node has enough balance for a competing slot
- """
- self.add_node_to_experiment(self.create_node())
- self.nodes[1].overlay.settings.peer_flags.add(PEER_FLAG_EXIT_BT)
- await self.introduce_nodes()
- self.nodes[1].overlay.random_slots = []
- self.nodes[1].overlay.competing_slots = [(-1000, 1234)]
- self.nodes[0].overlay.build_tunnels(1)
- await self.deliver_messages()
-
- # Assert whether we didn't create the circuit
- self.assertEqual(self.nodes[0].overlay.tunnels_ready(1), 1.0)
-
- async def test_empty_competing_slot(self):
- """
- Test whether a circuit is created when a node takes an empty competing slot
- """
- self.add_node_to_experiment(self.create_node())
- self.nodes[1].overlay.settings.peer_flags.add(PEER_FLAG_EXIT_BT)
- await self.introduce_nodes()
- self.nodes[1].overlay.random_slots = []
- self.nodes[1].overlay.competing_slots = [(0, None)]
- self.nodes[0].overlay.build_tunnels(1)
- await self.deliver_messages()
-
- # Assert whether we did create the circuit
- self.assertEqual(self.nodes[0].overlay.tunnels_ready(1), 1.0)
-
- async def test_win_competing_slot_exit(self):
- """
- Test whether a two-hop circuit is created when a node has enough balance for a competing slot at the exit
- """
- self.add_node_to_experiment(self.create_node())
- self.add_node_to_experiment(self.create_node())
- self.nodes[2].overlay.settings.peer_flags.add(PEER_FLAG_EXIT_BT)
- await self.introduce_nodes()
- self.nodes[2].overlay.random_slots = []
- self.nodes[2].overlay.competing_slots = [(-1000, 1234)]
- self.nodes[0].overlay.build_tunnels(2)
- await self.deliver_messages()
-
- # Assert whether we did create the circuit
- self.assertEqual(self.nodes[0].overlay.tunnels_ready(2), 1.0)
-
- async def test_win_competing_slot_relay(self):
- """
- Test whether a two-hop circuit is created when a node has enough balance for a competing slot
- """
- self.add_node_to_experiment(self.create_node())
- self.add_node_to_experiment(self.create_node())
- self.nodes[2].overlay.settings.peer_flags.add(PEER_FLAG_EXIT_BT)
- await self.introduce_nodes()
- self.nodes[1].overlay.random_slots = []
- self.nodes[1].overlay.competing_slots = [(-1000, 1234)]
- self.nodes[0].overlay.build_tunnels(2)
- await self.deliver_messages()
-
- # Assert whether we did create the circuit
- self.assertEqual(self.nodes[0].overlay.tunnels_ready(2), 1.0)
-
- async def test_payout_on_competition_kick(self):
- """
- Test whether a payout is initiated when an existing node is kicked out from a competing slot
- """
- self.add_node_to_experiment(self.create_node())
- self.add_node_to_experiment(self.create_node())
- self.nodes[2].overlay.settings.peer_flags.add(PEER_FLAG_EXIT_BT)
- await self.introduce_nodes()
-
- # Make sure that there's a token disbalance between node 0 and 1
- await self.nodes[0].overlay.bandwidth_community.do_payout(self.nodes[1].my_peer, 1024 * 1024)
-
- self.nodes[2].overlay.random_slots = []
- self.nodes[2].overlay.competing_slots = [(0, None)]
- self.nodes[0].overlay.build_tunnels(1)
- await self.deliver_messages()
-
- # Let some artificial data flow over the circuit
- list(self.nodes[0].overlay.circuits.values())[0].bytes_down = 250 * 1024 * 1024
-
- self.assertEqual(self.nodes[0].overlay.tunnels_ready(1), 1.0)
- self.assertTrue(self.nodes[2].overlay.exit_sockets)
-
- self.nodes[1].overlay.build_tunnels(1)
- await self.deliver_messages()
- self.assertTrue(self.nodes[2].overlay.exit_sockets)
- self.assertEqual(self.nodes[1].overlay.tunnels_ready(1), 1.0)
-
- # Check whether the exit node has been paid
- self.assertGreaterEqual(self.nodes[2].overlay.bandwidth_community.database.get_my_balance(), 250 * 1024 * 1024)
-
async def test_intro_point_slot(self):
"""
Test whether a introduction point occupies a slot
@@ -550,36 +327,6 @@ async def test_intro_point_slot(self):
await self.deliver_messages()
self.assertFalse(exit_socket.circuit_id in self.nodes[1].overlay.random_slots)
- async def test_reject_callback(self):
- """
- Test whether the rejection callback is correctly invoked when a circuit request is rejected
- """
- reject_future = Future()
- self.add_node_to_experiment(self.create_node())
- self.nodes[1].overlay.settings.peer_flags.add(PEER_FLAG_EXIT_BT)
- await self.introduce_nodes()
-
- # Make sure that there's a token disbalance between node 0 and 1
- await self.nodes[0].overlay.bandwidth_community.do_payout(self.nodes[1].my_peer, 1024 * 1024)
-
- def on_reject(_, balance):
- self.assertEqual(balance, -1024 * 1024)
- reject_future.set_result(None)
-
- self.nodes[1].overlay.reject_callback = on_reject
-
- # Initialize the slots
- self.nodes[1].overlay.random_slots = []
- self.nodes[1].overlay.competing_slots = [(100000000, 12345)]
-
- self.nodes[0].overlay.build_tunnels(1)
- await self.deliver_messages()
-
- self.assertEqual(self.nodes[0].overlay.tunnels_ready(1), 0.0)
-
- # Node 0 should be rejected and the reject callback should be invoked by node 1
- await reject_future
-
async def test_perform_http_request(self):
"""
Test whether we can make a http request through a circuit
@@ -664,7 +411,7 @@ async def test_perform_http_request_failed(self):
def test_cache_exitnodes_to_disk(self):
""" Test whether we can cache exit nodes to disk """
- self.overlay(0).candidates = {Peer(LibNaCLPK(b'\x00'*64), ("0.1.2.3", 1029)): {PEER_FLAG_EXIT_BT}}
+ self.overlay(0).candidates = {Peer(LibNaCLPK(b'\x00' * 64), ("0.1.2.3", 1029)): {PEER_FLAG_EXIT_BT}}
self.overlay(0).exitnode_cache = self.tmp_path / 'exitnode_cache.dat'
self.overlay(0).cache_exitnodes_to_disk()
@@ -672,8 +419,19 @@ def test_cache_exitnodes_to_disk(self):
def test_cache_exitnodes_to_disk_os_error(self):
""" Test whether we can handle an OSError when caching exit nodes to disk and raise no errors """
- self.overlay(0).candidates = {Peer(LibNaCLPK(b'\x00'*64), ("0.1.2.3", 1029)): {PEER_FLAG_EXIT_BT}}
+ self.overlay(0).candidates = {Peer(LibNaCLPK(b'\x00' * 64), ("0.1.2.3", 1029)): {PEER_FLAG_EXIT_BT}}
self.overlay(0).exitnode_cache = Mock(write_bytes=Mock(side_effect=FileNotFoundError))
self.overlay(0).cache_exitnodes_to_disk()
assert self.overlay(0).exitnode_cache.write_bytes.called
+
+ async def test_should_join_circuit(self):
+ """ Test whether we can join a circuit"""
+ community: TriblerTunnelCommunity = self.overlay(0)
+ assert await community.should_join_circuit(create_payload=Mock(), previous_node_address=Mock())
+
+ async def test_should_join_circuit_no_slots(self):
+ """ Test whether we can not join a circuit when we have no slots"""
+ community: TriblerTunnelCommunity = self.overlay(0)
+ community.random_slots = []
+ assert not await community.should_join_circuit(create_payload=Mock(), previous_node_address=Mock())
diff --git a/src/tribler/core/components/tunnel/tunnel_component.py b/src/tribler/core/components/tunnel/tunnel_component.py
index ae89702fb95..10fce6db51e 100644
--- a/src/tribler/core/components/tunnel/tunnel_component.py
+++ b/src/tribler/core/components/tunnel/tunnel_component.py
@@ -1,7 +1,6 @@
from ipv8.dht.provider import DHTCommunityProvider
from ipv8.messaging.anonymization.community import TunnelSettings
-from tribler.core.components.bandwidth_accounting.bandwidth_accounting_component import BandwidthAccountingComponent
from tribler.core.components.component import Component
from tribler.core.components.ipv8.ipv8_component import INFINITE, Ipv8Component
from tribler.core.components.libtorrent.libtorrent_component import LibtorrentComponent
@@ -24,9 +23,6 @@ async def run(self):
self._ipv8_component = await self.require_component(Ipv8Component)
dht_discovery_community = self._ipv8_component.dht_discovery_community
- bandwidth_component = await self.get_component(BandwidthAccountingComponent)
- bandwidth_community = bandwidth_component.community if bandwidth_component else None
-
download_component = await self.get_component(LibtorrentComponent)
download_manager = download_component.download_manager if download_component else None
@@ -46,7 +42,6 @@ async def run(self):
provider = DHTCommunityProvider(dht_discovery_community, config.ipv8.port) if dht_discovery_community else None
exitnode_cache = config.state_dir / "exitnode_cache.dat"
- # TODO: decouple bandwidth community and dlmgr to initiate later
self.community = tunnel_cls(self._ipv8_component.peer,
self._ipv8_component.ipv8.endpoint,
self._ipv8_component.ipv8.network,
@@ -54,7 +49,6 @@ async def run(self):
config=config.tunnel_community,
notifier=self.session.notifier,
dlmgr=download_manager,
- bandwidth_community=bandwidth_community,
dht_provider=provider,
exitnode_cache=exitnode_cache,
settings=settings)
diff --git a/src/tribler/core/config/tribler_config.py b/src/tribler/core/config/tribler_config.py
index ccee0b92a30..64df1ee6efa 100644
--- a/src/tribler/core/config/tribler_config.py
+++ b/src/tribler/core/config/tribler_config.py
@@ -9,7 +9,6 @@
from configobj import ParseError
from pydantic import BaseSettings, Extra, PrivateAttr, validate_model
-from tribler.core.components.bandwidth_accounting.settings import BandwidthAccountingSettings
from tribler.core.components.ipv8.settings import (
BootstrapSettings,
DHTSettings,
@@ -40,7 +39,6 @@ class Config:
general: GeneralSettings = GeneralSettings()
tunnel_community: TunnelCommunitySettings = TunnelCommunitySettings()
- bandwidth_accounting: BandwidthAccountingSettings = BandwidthAccountingSettings()
bootstrap: BootstrapSettings = BootstrapSettings()
ipv8: Ipv8Settings = Ipv8Settings()
discovery_community: DiscoveryCommunitySettings = DiscoveryCommunitySettings()
diff --git a/src/tribler/core/start_core.py b/src/tribler/core/start_core.py
index 23502f43d0f..cad77af6818 100644
--- a/src/tribler/core/start_core.py
+++ b/src/tribler/core/start_core.py
@@ -3,7 +3,6 @@
import logging.config
import os
import signal
-import sys
from pathlib import Path
from typing import List, Optional
@@ -12,8 +11,8 @@
check_and_enable_code_tracing,
set_process_priority,
)
-from tribler.core.components.bandwidth_accounting.bandwidth_accounting_component import BandwidthAccountingComponent
from tribler.core.components.component import Component
+from tribler.core.components.content_discovery.content_discovery_component import ContentDiscoveryComponent
from tribler.core.components.database.database_component import DatabaseComponent
from tribler.core.components.gui_process_watcher.gui_process_watcher import GuiProcessWatcher
from tribler.core.components.gui_process_watcher.gui_process_watcher_component import GuiProcessWatcherComponent
@@ -21,8 +20,6 @@
from tribler.core.components.key.key_component import KeyComponent
from tribler.core.components.knowledge.knowledge_component import KnowledgeComponent
from tribler.core.components.libtorrent.libtorrent_component import LibtorrentComponent
-from tribler.core.components.payout.payout_component import PayoutComponent
-from tribler.core.components.content_discovery.content_discovery_component import ContentDiscoveryComponent
from tribler.core.components.reporter.exception_handler import default_core_exception_handler
from tribler.core.components.reporter.reporter_component import ReporterComponent
from tribler.core.components.resource_monitor.resource_monitor_component import ResourceMonitorComponent
@@ -65,8 +62,6 @@ def components_gen(config: TriblerConfig):
if config.libtorrent.enabled:
yield LibtorrentComponent()
- if config.ipv8.enabled:
- yield BandwidthAccountingComponent()
if config.resource_monitor.enabled:
yield ResourceMonitorComponent()
@@ -84,8 +79,6 @@ def components_gen(config: TriblerConfig):
if config.ipv8.enabled and config.tunnel_community.enabled:
yield TunnelsComponent()
- if config.ipv8.enabled:
- yield PayoutComponent()
yield WatchFolderComponent()
if config.general.version_checker_enabled:
yield VersionCheckComponent()
diff --git a/src/tribler/core/tests/tools/data/upgrade_databases/bandwidth_v8.db b/src/tribler/core/tests/tools/data/upgrade_databases/bandwidth_v8.db
deleted file mode 100644
index b7138b418a7..00000000000
Binary files a/src/tribler/core/tests/tools/data/upgrade_databases/bandwidth_v8.db and /dev/null differ
diff --git a/src/tribler/core/upgrade/tests/test_upgrader.py b/src/tribler/core/upgrade/tests/test_upgrader.py
index eea1831b546..7e86ded7eb7 100644
--- a/src/tribler/core/upgrade/tests/test_upgrader.py
+++ b/src/tribler/core/upgrade/tests/test_upgrader.py
@@ -7,9 +7,8 @@
import pytest
from ipv8.keyvault.private.libnaclkey import LibNaCLSK
-from pony.orm import db_session, select
+from pony.orm import db_session
-from tribler.core.components.bandwidth_accounting.db.database import BandwidthDatabase
from tribler.core.components.database.db.orm_bindings.torrent_metadata import CHANNEL_DIR_NAME_LENGTH
from tribler.core.components.database.db.store import CURRENT_DB_VERSION, MetadataStore
from tribler.core.tests.tools.common import TESTS_DATA_DIR
@@ -19,6 +18,7 @@
cleanup_noncompliant_channel_torrents
from tribler.core.utilities.configparser import CallbackConfigParser
from tribler.core.utilities.db_corruption_handling.base import DatabaseIsCorrupted
+from tribler.core.utilities.simpledefs import STATEDIR_DB_DIR
from tribler.core.utilities.utilities import random_infohash
@@ -326,19 +326,6 @@ def test_calc_progress():
assert calc_progress(1000, 100) == pytest.approx(99.158472, abs=EPSILON)
-def test_upgrade_bw_accounting_db_8to9(upgrader, state_dir, trustchain_keypair):
- bandwidth_path = state_dir / 'sqlite/bandwidth.db'
- _copy('bandwidth_v8.db', bandwidth_path)
-
- upgrader.upgrade_bw_accounting_db_8to9()
- db = BandwidthDatabase(bandwidth_path, trustchain_keypair.key.pk)
- with db_session:
- assert not list(select(tx for tx in db.BandwidthTransaction))
- assert not list(select(item for item in db.BandwidthHistory))
- assert int(db.MiscData.get(name="db_version").value) == 9
- db.shutdown()
-
-
def test_remove_old_logs(upgrader: TriblerUpgrader, state_dir: Path, tmp_path):
"""Ensure that the `remove_old_logs` function removes only logs"""
@@ -403,3 +390,20 @@ def patched_unlink(self, *_, **__):
assert left == [side_effect_log_file]
assert not normal_log_file.exists()
assert side_effect_log_file.exists()
+
+
+def test_remove_bandwidth_db(upgrader: TriblerUpgrader, state_dir: Path):
+ """ Ensure that the `remove_bandwidth_db` function removes only bandwidth db files"""
+ db_path = Path(state_dir / STATEDIR_DB_DIR)
+
+ (db_path / 'bandwidth.db').touch()
+ (db_path / 'bandwidth.db-shm').touch()
+ (db_path / 'bandwidth.db-wal').touch()
+ (db_path / 'knowledge.db').touch()
+
+ assert len(list(db_path.glob('*'))) == 4
+ assert len(list(db_path.glob('bandwidth*'))) == 3
+
+ upgrader.remove_bandwidth_db()
+
+ assert len(list(db_path.glob('bandwidth*'))) == 0
diff --git a/src/tribler/core/upgrade/upgrade.py b/src/tribler/core/upgrade/upgrade.py
index 3d7be8a921f..6f588e99306 100644
--- a/src/tribler/core/upgrade/upgrade.py
+++ b/src/tribler/core/upgrade/upgrade.py
@@ -3,14 +3,14 @@
import shutil
import time
from configparser import MissingSectionHeaderError, ParsingError
+from contextlib import suppress
from functools import wraps
from types import SimpleNamespace
from typing import List, Optional, Tuple
from ipv8.keyvault.private.libnaclkey import LibNaCLSK
-from pony.orm import db_session, delete
+from pony.orm import db_session
-from tribler.core.components.bandwidth_accounting.db.database import BandwidthDatabase
from tribler.core.components.database.db.orm_bindings.torrent_metadata import CHANNEL_DIR_NAME_LENGTH
from tribler.core.components.database.db.store import (
CURRENT_DB_VERSION, MetadataStore,
@@ -130,7 +130,6 @@ def run(self):
self.upgrade_pony_db_8to10()
self.upgrade_pony_db_10to11()
convert_config_to_tribler76(self.state_dir)
- self.upgrade_bw_accounting_db_8to9()
self.upgrade_pony_db_11to12()
self.upgrade_pony_db_12to13()
self.upgrade_pony_db_13to14()
@@ -138,6 +137,7 @@ def run(self):
self.remove_old_logs()
self.upgrade_pony_db_14to15()
self.upgrade_knowledge_to_tribler_db()
+ self.remove_bandwidth_db()
migration_chain = TriblerDatabaseMigrationChain(self.state_dir)
migration_chain.execute()
@@ -268,35 +268,6 @@ def upgrade_pony_db_10to11(self):
self.do_upgrade_pony_db_10to11(mds)
mds.shutdown()
- @catch_db_is_corrupted_exception
- def upgrade_bw_accounting_db_8to9(self):
- """
- Upgrade the database with bandwidth accounting information from 8 to 9.
- Specifically, this upgrade wipes all transactions and addresses an issue where payouts with the wrong amount
- were made. Also see https://github.com/Tribler/tribler/issues/5789.
- """
- self._logger.info('Upgrade bandwidth accounting DB 8 to 9')
- to_version = 9
-
- database_path = self.state_dir / STATEDIR_DB_DIR / 'bandwidth.db'
- if not database_path.exists() or get_db_version(database_path, BandwidthDatabase.CURRENT_DB_VERSION) > 8:
- # No need to update if the database does not exist or is already updated
- return # pragma: no cover
-
- self._logger.info('bw8->9')
- db = BandwidthDatabase(database_path, self.primary_key.key.pk)
-
- # Wipe all transactions and bandwidth history
- with db_session:
- delete(tx for tx in db.BandwidthTransaction)
- delete(item for item in db.BandwidthHistory)
-
- # Update db version
- db_version = db.MiscData.get(name="db_version")
- db_version.value = str(to_version)
-
- db.shutdown()
-
def column_exists_in_table(self, db, table, column):
pragma = f'SELECT COUNT(*) FROM pragma_table_info("{table}") WHERE name="{column}"'
result = list(db.execute(pragma))
@@ -488,3 +459,13 @@ def upgrade_knowledge_to_tribler_db(self):
self._logger.info('Upgrade knowledge to tribler.db')
migration = MigrationKnowledgeToTriblerDB(self.state_dir)
migration.run()
+
+ def remove_bandwidth_db(self):
+ self._logger.info('Removing bandwidth database')
+
+ db_path = Path(self.state_dir / STATEDIR_DB_DIR)
+
+ for file_path in db_path.glob('bandwidth*'):
+ self._logger.info(f'Removing {file_path}')
+ with suppress(OSError):
+ file_path.unlink(missing_ok=True)
diff --git a/src/tribler/gui/debug_window.py b/src/tribler/gui/debug_window.py
index c6544dc77ce..e15b9292802 100644
--- a/src/tribler/gui/debug_window.py
+++ b/src/tribler/gui/debug_window.py
@@ -6,7 +6,6 @@
import sys
from binascii import unhexlify
from time import localtime, strftime, time
-from typing import Dict
import libtorrent
import psutil
@@ -179,8 +178,6 @@ def tab_changed(self, index):
self.load_general_tab()
elif index == 1:
self.load_requests_tab()
- elif index == 2:
- self.run_with_timer(self.load_bandwidth_accounting_tab)
elif index == 3:
self.ipv8_tab_changed(self.window().ipv8_tab_widget.currentIndex())
elif index == 4:
@@ -324,23 +321,6 @@ def load_requests_tab(self):
item.setText(2, f"{strftime('%H:%M:%S', localtime(timestamp))}")
self.window().requests_tree_widget.addTopLevelItem(item)
- def load_bandwidth_accounting_tab(self) -> None:
- """
- Initiate a request to the Tribler core to fetch statistics on bandwidth accounting.
- """
- request_manager.get("bandwidth/statistics", self.on_bandwidth_statistics)
-
- def on_bandwidth_statistics(self, data: Dict) -> None:
- """
- We received bandwidth statistics from the core.
- :param data: The bandwidth statistics, in JSON format.
- """
- if not data:
- return
- self.window().bandwidth_tree_widget.clear()
- for key, value in data["statistics"].items():
- self.create_and_add_widget_item(key, value, self.window().bandwidth_tree_widget)
-
def load_ipv8_general_tab(self):
request_manager.get("statistics/ipv8", self.on_ipv8_general_stats)
diff --git a/src/tribler/gui/qt_resources/debugwindow.ui b/src/tribler/gui/qt_resources/debugwindow.ui
index 9c0866ac45a..eb13b7ce3ab 100644
--- a/src/tribler/gui/qt_resources/debugwindow.ui
+++ b/src/tribler/gui/qt_resources/debugwindow.ui
@@ -112,49 +112,7 @@
-
-
- Bandwidth Accounting
-
-
-
- 0
-
-
- 0
-
-
- 0
-
-
- 0
-
-
- 0
-
- -
-
-
- 2
-
-
- 200
-
-
-
- Key
-
-
-
-
- Value
-
-
-
-
-
-
-
+
IPv8
@@ -413,7 +371,7 @@
-
+
Tunnels
@@ -747,7 +705,7 @@
-
+
DHT
@@ -862,7 +820,7 @@
-
+
Events
@@ -920,7 +878,7 @@
-
+
System
diff --git a/src/tribler/gui/tests/test_gui.py b/src/tribler/gui/tests/test_gui.py
index 350c25bc03a..d08457514da 100644
--- a/src/tribler/gui/tests/test_gui.py
+++ b/src/tribler/gui/tests/test_gui.py
@@ -315,8 +315,6 @@ def test_settings(window):
screenshot(window, name="settings_general")
QTest.mouseClick(window.settings_connection_button, Qt.LeftButton)
screenshot(window, name="settings_connection")
- QTest.mouseClick(window.settings_bandwidth_button, Qt.LeftButton)
- screenshot(window, name="settings_bandwidth")
QTest.mouseClick(window.settings_seeding_button, Qt.LeftButton)
screenshot(window, name="settings_seeding")
QTest.mouseClick(window.settings_anonymity_button, Qt.LeftButton)
@@ -497,10 +495,6 @@ def test_debug_pane(window):
wait_for_list_populated(window.debug_window.requests_tree_widget)
screenshot(window.debug_window, name="debug_panel_requests_tab")
- window.debug_window.debug_tab_widget.setCurrentIndex(2)
- wait_for_list_populated(window.debug_window.bandwidth_tree_widget)
- screenshot(window.debug_window, name="debug_panel_bandwidth_tab")
-
window.debug_window.debug_tab_widget.setCurrentIndex(3)
wait_for_list_populated(window.debug_window.ipv8_general_tree_widget)
screenshot(window.debug_window, name="debug_panel_ipv8_tab")