From bfa1394cd6d7ffa946d8fe113ea1fb67947578e4 Mon Sep 17 00:00:00 2001 From: Martijn de Vos Date: Fri, 2 Mar 2018 17:03:41 +0100 Subject: [PATCH 1/3] Implemented payouts --- .../Core/APIImplementation/LaunchManyCore.py | 3 +- .../Community/Triblerchain/test_community.py | 39 +---- .../Test/Community/Tunnel/test_community.py | 139 +++++++++++++++++- .../Modules/RestApi/test_debug_endpoint.py | 2 + Tribler/Test/mocking/exit_socket.py | 40 +++++ Tribler/community/triblerchain/community.py | 47 ------ Tribler/community/triblertunnel/community.py | 102 ++++++++++++- Tribler/community/triblertunnel/payload.py | 37 +++++ 8 files changed, 314 insertions(+), 95 deletions(-) create mode 100644 Tribler/Test/mocking/exit_socket.py create mode 100644 Tribler/community/triblertunnel/payload.py diff --git a/Tribler/Core/APIImplementation/LaunchManyCore.py b/Tribler/Core/APIImplementation/LaunchManyCore.py index 1bb8e259ccc..f8df9450b97 100644 --- a/Tribler/Core/APIImplementation/LaunchManyCore.py +++ b/Tribler/Core/APIImplementation/LaunchManyCore.py @@ -257,7 +257,8 @@ def load_ipv8_overlays(self): tribler_session=self.session, dht_provider=MainlineDHTProvider( self.mainline_dht, - self.session.config.get_dispersy_port())) + self.session.config.get_dispersy_port()), + triblerchain_community=self.triblerchain_community) self.ipv8.overlays.append(self.tunnel_community) self.ipv8.strategies.append((RandomWalk(self.tunnel_community), 20)) diff --git a/Tribler/Test/Community/Triblerchain/test_community.py b/Tribler/Test/Community/Triblerchain/test_community.py index 1bbe98e5fbf..1c6ebfcb627 100644 --- a/Tribler/Test/Community/Triblerchain/test_community.py +++ b/Tribler/Test/Community/Triblerchain/test_community.py @@ -1,43 +1,8 @@ -from Tribler.Test.Core.base_test import MockObject from Tribler.Test.ipv8_base import TestBase from Tribler.Test.mocking.ipv8 import MockIPv8 from Tribler.Test.util.ipv8_util import twisted_wrapper from Tribler.community.triblerchain.block import TriblerChainBlock -from Tribler.community.triblerchain.community import TriblerChainCommunity, TriblerChainCrawlerCommunity -from Tribler.pyipv8.ipv8.messaging.anonymization.tunnel import Circuit - - -class TestTriblerChainCommunity(TestBase): - - def setUp(self): - super(TestTriblerChainCommunity, self).setUp() - self.initialize(TriblerChainCommunity, 2) - self.nodes[0].overlay.SIGN_DELAY = 0 - self.nodes[1].overlay.SIGN_DELAY = 0 - - def create_node(self): - return MockIPv8(u"curve25519", TriblerChainCommunity, working_directory=u":memory:") - - @twisted_wrapper - def test_on_tunnel_remove(self): - """ - Test whether a message is created when a tunnel has been removed - """ - tribler_session = MockObject() - tribler_session.lm = MockObject() - tribler_session.lm.tunnel_community = MockObject() - tribler_session.lm.tunnel_community.network = self.nodes[0].overlay.network - self.nodes[0].overlay.tribler_session = tribler_session - - circuit = Circuit(3) - circuit.bytes_up = 50 * 1024 * 1024 - self.nodes[0].overlay.on_tunnel_remove(None, None, circuit, - self.nodes[0].overlay.network.verified_peers[0].address) - - yield self.sleep(time=0.1) - - my_pk = self.nodes[0].overlay.my_peer.public_key.key_to_bin() - self.assertTrue(self.nodes[0].overlay.persistence.get(my_pk, 1)) +from Tribler.community.triblerchain.community import TriblerChainCrawlerCommunity class TestTriblerChainCrawlerCommunity(TestBase): @@ -45,8 +10,6 @@ class TestTriblerChainCrawlerCommunity(TestBase): def setUp(self): super(TestTriblerChainCrawlerCommunity, self).setUp() self.initialize(TriblerChainCrawlerCommunity, 2) - self.nodes[0].overlay.SIGN_DELAY = 0 - self.nodes[1].overlay.SIGN_DELAY = 0 def create_node(self): return MockIPv8(u"curve25519", TriblerChainCrawlerCommunity, working_directory=u":memory:") diff --git a/Tribler/Test/Community/Tunnel/test_community.py b/Tribler/Test/Community/Tunnel/test_community.py index 523b4a69ab8..eb8b1b97deb 100644 --- a/Tribler/Test/Community/Tunnel/test_community.py +++ b/Tribler/Test/Community/Tunnel/test_community.py @@ -1,18 +1,94 @@ from Tribler.Test.Core.base_test import MockObject from Tribler.Test.ipv8_base import TestBase +from Tribler.Test.mocking.exit_socket import MockTunnelExitSocket from Tribler.Test.mocking.ipv8 import MockIPv8 +from Tribler.Test.util.ipv8_util import twisted_wrapper +from Tribler.community.triblerchain.community import TriblerChainCommunity from Tribler.community.triblertunnel.community import TriblerTunnelCommunity +from Tribler.pyipv8.ipv8.messaging.anonymization.tunnel import CIRCUIT_TYPE_RENDEZVOUS +from Tribler.pyipv8.ipv8.peer import Peer from Tribler.pyipv8.ipv8.util import blocking_call_on_reactor_thread +from twisted.internet.defer import inlineCallbacks + + +# Map of info_hash -> peer list +global_dht_services = {} + + +class MockDHTProvider(object): + + def __init__(self, address): + self.address = address + + def lookup(self, info_hash, cb): + if info_hash in global_dht_services: + cb(info_hash, global_dht_services[info_hash], None) + + def announce(self, info_hash): + if info_hash in global_dht_services: + global_dht_services[info_hash].append(self.address) + else: + global_dht_services[info_hash] = [self.address] class TestTriblerTunnelCommunity(TestBase): def setUp(self): super(TestTriblerTunnelCommunity, self).setUp() + self.private_nodes = [] self.initialize(TriblerTunnelCommunity, 1) + def tearDown(self): + super(TestTriblerTunnelCommunity, self).tearDown() + + for node in self.private_nodes: + node.unload() + def create_node(self): - return MockIPv8(u"curve25519", TriblerTunnelCommunity) + mock_ipv8 = MockIPv8(u"curve25519", TriblerTunnelCommunity, socks_listen_ports=[]) + mock_ipv8.overlay._use_main_thread = False + + # Load the TriblerChain community + overlay = TriblerChainCommunity(mock_ipv8.my_peer, mock_ipv8.endpoint, mock_ipv8.network, + working_directory=u":memory:") + mock_ipv8.overlay.triblerchain_community = overlay + mock_ipv8.overlay.dht_provider = MockDHTProvider(mock_ipv8.endpoint.wan_address) + + return mock_ipv8 + + @inlineCallbacks + def create_intro(self, node_nr, service): + """ + Create an 1 hop introduction point for some node for some service. + """ + lookup_service = self.nodes[node_nr].overlay.get_lookup_info_hash(service) + self.nodes[node_nr].overlay.hops[lookup_service] = 1 + self.nodes[node_nr].overlay.create_introduction_point(lookup_service) + + yield self.deliver_messages() + + for node in self.nodes: + exit_sockets = node.overlay.exit_sockets + for exit_socket in exit_sockets: + exit_sockets[exit_socket] = MockTunnelExitSocket(exit_sockets[exit_socket]) + + @inlineCallbacks + def assign_exit_node(self, node_nr): + """ + Give a node a dedicated exit node to play with. + """ + exit_node = self.create_node() + self.private_nodes.append(exit_node) + exit_node.overlay.settings.become_exitnode = True + public_peer = Peer(exit_node.my_peer.public_key, exit_node.my_peer.address) + self.nodes[node_nr].network.add_verified_peer(public_peer) + self.nodes[node_nr].network.discover_services(public_peer, exit_node.overlay.master_peer.mid) + self.nodes[node_nr].overlay.update_exit_candidates(public_peer, True) + self.nodes[node_nr].overlay.build_tunnels(1) + yield self.deliver_messages() + exit_sockets = exit_node.overlay.exit_sockets + for exit_socket in exit_sockets: + exit_sockets[exit_socket] = MockTunnelExitSocket(exit_sockets[exit_socket]) @blocking_call_on_reactor_thread def test_download_remove(self): @@ -143,3 +219,64 @@ def test_update_torrent(self): # Test adding peers self.nodes[0].overlay.bittorrent_peers['a'] = {4} self.nodes[0].overlay.update_torrent(peers, mock_handle, 'a') + + @twisted_wrapper + 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()) + + # Build a tunnel + self.nodes[2].overlay.settings.become_exitnode = True + yield self.introduce_nodes() + self.nodes[0].overlay.build_tunnels(2) + yield self.deliver_messages() + + self.assertEqual(self.nodes[0].overlay.tunnels_ready(2), 1.0) + + # Destroy the circuit + for circuit_id, circuit in self.nodes[0].overlay.circuits.items(): + circuit.bytes_down = 250 * 1024 * 1024 + self.nodes[0].overlay.remove_circuit(circuit_id, destroy=True) + + yield self.deliver_messages() + + # Verify whether the downloader (node 0) correctly paid the relay and exit nodes. + self.assertTrue(self.nodes[0].overlay.triblerchain_community.get_bandwidth_tokens() < 0) + self.assertTrue(self.nodes[1].overlay.triblerchain_community.get_bandwidth_tokens() > 0) + self.assertTrue(self.nodes[2].overlay.triblerchain_community.get_bandwidth_tokens() > 0) + + @twisted_wrapper + 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 = '0' * 20 + + self.nodes[0].overlay.register_service(service, 1, None, 0) + + yield self.introduce_nodes() + yield self.create_intro(2, service) + yield self.assign_exit_node(0) + + self.nodes[0].overlay.do_dht_lookup(service) + + yield self.deliver_messages(timeout=.2) + + # Destroy the e2e-circuit + for circuit_id, circuit in self.nodes[0].overlay.circuits.items(): + if circuit.ctype == CIRCUIT_TYPE_RENDEZVOUS: + circuit.bytes_down = 250 * 1024 * 1024 + self.nodes[0].overlay.remove_circuit(circuit_id, destroy=True) + + yield self.deliver_messages() + + # Verify whether the downloader (node 0) correctly paid the subsequent nodes. + self.assertTrue(self.nodes[0].overlay.triblerchain_community.get_bandwidth_tokens() < 0) + self.assertTrue(self.nodes[1].overlay.triblerchain_community.get_bandwidth_tokens() > 0) + self.assertTrue(self.nodes[2].overlay.triblerchain_community.get_bandwidth_tokens() > 0) diff --git a/Tribler/Test/Core/Modules/RestApi/test_debug_endpoint.py b/Tribler/Test/Core/Modules/RestApi/test_debug_endpoint.py index a3be553a362..1f748b0408f 100644 --- a/Tribler/Test/Core/Modules/RestApi/test_debug_endpoint.py +++ b/Tribler/Test/Core/Modules/RestApi/test_debug_endpoint.py @@ -4,6 +4,7 @@ from Tribler.Test.Core.Modules.RestApi.base_api_test import AbstractApiTest from Tribler.Test.Core.base_test import MockObject from Tribler.Test.twisted_thread import deferred +from Tribler.pyipv8.ipv8.messaging.anonymization.tunnel import CIRCUIT_TYPE_DATA class TestCircuitDebugEndpoint(AbstractApiTest): @@ -40,6 +41,7 @@ def test_get_circuits(self): mock_circuit.hops = [mock_hop] mock_circuit.sock_addr = ("1.1.1.1", 1234) mock_circuit.circuit_id = 1234 + mock_circuit.ctype = CIRCUIT_TYPE_DATA mock_circuit.destroy = lambda: None self.session.lm.tunnel_community.circuits = {1234: mock_circuit} diff --git a/Tribler/Test/mocking/exit_socket.py b/Tribler/Test/mocking/exit_socket.py new file mode 100644 index 00000000000..6d98e2ee20d --- /dev/null +++ b/Tribler/Test/mocking/exit_socket.py @@ -0,0 +1,40 @@ +from __future__ import absolute_import + +from Tribler.Test.mocking.endpoint import AutoMockEndpoint +from Tribler.pyipv8.ipv8.messaging.anonymization.tunnel import TunnelExitSocket, DataChecker +from Tribler.pyipv8.ipv8.messaging.interfaces.endpoint import EndpointListener +from twisted.internet.defer import succeed + + + +class MockTunnelExitSocket(TunnelExitSocket, EndpointListener): + + def __init__(self, parent): + self.endpoint = AutoMockEndpoint() + self.endpoint.open() + + TunnelExitSocket.__init__(self, parent.circuit_id, parent.overlay, parent.sock_addr, parent.mid) + parent.close() + EndpointListener.__init__(self, self.endpoint) + + self.endpoint.add_listener(self) + + def enable(self): + pass + + @property + def enabled(self): + return True + + def sendto(self, data, destination): + if DataChecker.is_allowed(data): + self.endpoint.send(destination, data) + else: + raise AssertionError("Attempted to exit data which is not allowed" % repr(data)) + + def on_packet(self, packet): + source_address, data = packet + self.datagramReceived(data, source_address) + + def close(self): + return succeed(True) diff --git a/Tribler/community/triblerchain/community.py b/Tribler/community/triblerchain/community.py index 509c2bc7337..fb132f3e061 100644 --- a/Tribler/community/triblerchain/community.py +++ b/Tribler/community/triblerchain/community.py @@ -36,7 +36,6 @@ class TriblerChainCommunity(TrustChainCommunity): """ BLOCK_CLASS = TriblerChainBlock DB_CLASS = TriblerChainDB - SIGN_DELAY = 5 master_peer = Peer("3081a7301006072a8648ce3d020106052b81040027038192000405c66d3deddb1721787a247b2285118c06ce9fb" "20ebd3546969fa2f4811fa92426637423d3bac1510f92b33e2ff5a785bf54eb3b28d29a77d557011d7d5241243c" "9c89c987cd049404c4024999e1505fa96e1d6668234bde28a666d458d67251d17ff45185515a28967ddcf50503c" @@ -45,11 +44,6 @@ class TriblerChainCommunity(TrustChainCommunity): def __init__(self, *args, **kwargs): self.tribler_session = kwargs.pop('tribler_session', None) super(TriblerChainCommunity, self).__init__(*args, **kwargs) - self.notifier = None - - if self.tribler_session: - self.notifier = self.tribler_session.notifier - self.notifier.add_observer(self.on_tunnel_remove, NTFY_TUNNEL, [NTFY_REMOVE]) # We store the bytes send and received in the tunnel community in a dictionary. # The key is the public key of the peer being interacted with, the value a tuple of the up and down bytes @@ -85,51 +79,10 @@ def get_statistics(self, public_key=None): statistics["total_down"] = 0 return statistics - def on_tunnel_remove(self, subject, change_type, tunnel, sock_addr): - """ - Handler for the remove event of a tunnel. This function will attempt to create a block for the amounts that - were transferred using the tunnel. - :param subject: Category of the notifier event - :param change_type: Type of the notifier event - :param tunnel: The tunnel that was removed (closed) - :param sock_addr: The address of the peer with whom this node has interacted in the tunnel - """ - tunnel_peer = None - for verified_peer in self.tribler_session.lm.tunnel_community.network.verified_peers: - if verified_peer.address == sock_addr: - tunnel_peer = verified_peer - break - - if not tunnel_peer: - self.logger.warning("Could not find interacting peer for signing a TriblerChain block!") - return - - up = tunnel.bytes_up - down = tunnel.bytes_down - pk = tunnel_peer.public_key.key_to_bin() - - # If the transaction is not big enough we discard the bytes up and down. - if up + down >= MIN_TRANSACTION_SIZE: - # Tie breaker to prevent both parties from requesting - if up > down or (up == down and self.my_peer.public_key.key_to_bin() > pk): - self.register_task("sign_%s" % tunnel.circuit_id, - reactor.callLater(self.SIGN_DELAY, self.sign_block, tunnel_peer, pk, - {'up': tunnel.bytes_up, 'down': tunnel.bytes_down})) - else: - pend = self.pending_bytes.get(pk) - if not pend: - task = self.register_task("cleanup_pending_%s" % tunnel.circuit_id, - reactor.callLater(2 * 60, self.cleanup_pending, pk)) - self.pending_bytes[pk] = PendingBytes(up, down, task) - else: - pend.add(up, down) - def cleanup_pending(self, public_key): self.pending_bytes.pop(public_key, None) def unload(self): - if self.notifier: - self.notifier.remove_observer(self.on_tunnel_remove) for pk in self.pending_bytes: if self.pending_bytes[pk].clean is not None: self.pending_bytes[pk].clean.reset(0) diff --git a/Tribler/community/triblertunnel/community.py b/Tribler/community/triblertunnel/community.py index 04ea658425b..6ab94e0d98f 100644 --- a/Tribler/community/triblertunnel/community.py +++ b/Tribler/community/triblertunnel/community.py @@ -1,5 +1,7 @@ import time +from Tribler.community.triblertunnel.payload import PayoutPayload +from Tribler.pyipv8.ipv8.deprecated.payload_headers import GlobalTimeDistributionPayload from twisted.internet.defer import inlineCallbacks from Tribler.community.triblertunnel.dispatcher import TunnelDispatcher @@ -10,7 +12,8 @@ from Tribler.pyipv8.ipv8.messaging.anonymization.community import CreatePayload from Tribler.pyipv8.ipv8.messaging.anonymization.hidden_services import HiddenTunnelCommunity from Tribler.pyipv8.ipv8.messaging.anonymization.payload import LinkedE2EPayload -from Tribler.pyipv8.ipv8.messaging.anonymization.tunnel import CIRCUIT_STATE_READY, CIRCUIT_TYPE_RP +from Tribler.pyipv8.ipv8.messaging.anonymization.tunnel import CIRCUIT_STATE_READY, CIRCUIT_TYPE_RP, \ + CIRCUIT_TYPE_DATA, CIRCUIT_TYPE_RENDEZVOUS from Tribler.pyipv8.ipv8.peer import Peer @@ -22,14 +25,18 @@ class TriblerTunnelCommunity(HiddenTunnelCommunity): def __init__(self, *args, **kwargs): self.tribler_session = kwargs.pop('tribler_session', None) + self.triblerchain_community = kwargs.pop('triblerchain_community', None) + socks_listen_ports = kwargs.pop('socks_listen_ports', None) super(TriblerTunnelCommunity, self).__init__(*args, **kwargs) self._use_main_thread = True if self.tribler_session: self.settings.become_exitnode = self.tribler_session.config.get_tunnel_community_exitnode_enabled() - socks_listen_ports = self.tribler_session.config.get_tunnel_community_socks5_listen_ports() self.tribler_session.lm.tunnel_community = self - else: + + if not socks_listen_ports: + socks_listen_ports = self.tribler_session.config.get_tunnel_community_socks5_listen_ports() + elif socks_listen_ports is None: socks_listen_ports = range(1080, 1085) self.bittorrent_peers = {} @@ -45,6 +52,31 @@ def __init__(self, *args, **kwargs): self.dispatcher.set_socks_servers(self.socks_servers) + self.decode_map.update({ + chr(23): self.on_payout_block + }) + + def on_payout_block(self, source_address, data): + if not self.triblerchain_community: + self.logger.warning("Got payout while not having a TriblerChain community running!") + return + + _, payload = self._ez_unpack_noauth(PayoutPayload, data) + peer = Peer(payload.public_key, source_address) + block = self.triblerchain_community.BLOCK_CLASS.from_payload(payload, self.serializer) + self.triblerchain_community.process_half_block(block, peer) + + # Send the next payout + if payload.circuit_id in self.relay_from_to and block.transaction['down'] > payload.base_amount: + relay = self.relay_from_to[payload.circuit_id] + circuit_peer = self.get_peer_from_address(relay.sock_addr) + if not circuit_peer: + self.logger.warning("%s Unable to find next peer %s for payout!", self.my_peer, relay.mid.encode('hex')) + return + + self.do_payout(circuit_peer, relay.circuit_id, block.transaction['down'] - payload.base_amount * 2, + payload.base_amount) + def on_download_removed(self, download): """ This method is called when a download is removed. We check here whether we can stop building circuits for a @@ -75,7 +107,40 @@ def update_torrent(self, peers, handle, download): if self.active_data_circuits(): self.readd_bittorrent_peers() - def remove_circuit(self, circuit_id, additional_info='', destroy=False): + def get_peer_from_address(self, address): + circuit_peer = None + for peer in self.network.verified_peers: + if peer.address == address: + circuit_peer = peer + break + + return circuit_peer + + def do_payout(self, peer, circuit_id, amount, base_amount): + """ + 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 payouts. + """ + self.logger.info("Sending payout of %d (base: %d) to %s (cid: %s)", amount, base_amount, peer, circuit_id) + + block = self.triblerchain_community.BLOCK_CLASS.create( + {'up': 0, 'down': amount}, + self.triblerchain_community.persistence, + self.my_peer.public_key.key_to_bin(), + link_pk=peer.public_key.key_to_bin()) + block.sign(self.my_peer.key) + self.triblerchain_community.persistence.add_block(block) + + global_time = self.claim_global_time() + dist = GlobalTimeDistributionPayload(global_time).to_pack_list() + payload = PayoutPayload.from_half_block(block, circuit_id, base_amount).to_pack_list() + packet = self._ez_pack(self._prefix, 23, [dist, payload], False) + self.send_packet([peer], u"payout", packet) + + 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) return @@ -94,12 +159,30 @@ def remove_circuit(self, circuit_id, additional_info='', destroy=False): if s == ltmgr.get_session(d.get_hops()): d.get_handle().addCallback(lambda handle: self.update_torrent(affected_peers, handle, d)) + circuit_peer = self.get_peer_from_address(circuit.sock_addr) + if circuit.bytes_down >= 1024 * 1024 and self.triblerchain_community and circuit_peer: + # We should perform a payout of the removed circuit. + if circuit.ctype == CIRCUIT_TYPE_RENDEZVOUS: + # 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) + # Now we actually remove the circuit - super(TriblerTunnelCommunity, self).remove_circuit(circuit_id, additional_info=additional_info, destroy=destroy) + super(TriblerTunnelCommunity, self).remove_circuit(circuit_id, additional_info=additional_info, + remove_now=remove_now, destroy=destroy) - def remove_relay(self, circuit_id, additional_info='', destroy=False, got_destroy_from=None, both_sides=True): + def remove_relay(self, circuit_id, additional_info='', remove_now=False, destroy=False, got_destroy_from=None, + both_sides=True): removed_relays = super(TriblerTunnelCommunity, self).remove_relay(circuit_id, additional_info=additional_info, + remove_now=remove_now, destroy=destroy, got_destroy_from=got_destroy_from, both_sides=both_sides) @@ -108,13 +191,13 @@ def remove_relay(self, circuit_id, additional_info='', destroy=False, got_destro for removed_relay in removed_relays: self.tribler_session.notifier.notify(NTFY_TUNNEL, NTFY_REMOVE, removed_relay, removed_relay.sock_addr) - def remove_exit_socket(self, circuit_id, additional_info='', destroy=False): + def remove_exit_socket(self, circuit_id, additional_info='', remove_now=False, destroy=False): if circuit_id in self.exit_sockets and self.tribler_session: exit_socket = self.exit_sockets[circuit_id] self.tribler_session.notifier.notify(NTFY_TUNNEL, NTFY_REMOVE, exit_socket, exit_socket.sock_addr) super(TriblerTunnelCommunity, self).remove_exit_socket(circuit_id, additional_info=additional_info, - destroy=destroy) + remove_now=remove_now, destroy=destroy) def _ours_on_created_extended(self, circuit, payload): super(TriblerTunnelCommunity, self)._ours_on_created_extended(circuit, payload) @@ -211,6 +294,9 @@ def monitor_downloads(self, dslist): self.download_states = new_states def get_download(self, lookup_info_hash): + if not self.tribler_session: + return None + for download in self.tribler_session.get_downloads(): if lookup_info_hash == self.get_lookup_info_hash(download.get_def().get_infohash()): return download diff --git a/Tribler/community/triblertunnel/payload.py b/Tribler/community/triblertunnel/payload.py new file mode 100644 index 00000000000..de498f69abe --- /dev/null +++ b/Tribler/community/triblertunnel/payload.py @@ -0,0 +1,37 @@ +from Tribler.pyipv8.ipv8.attestation.trustchain.payload import HalfBlockPayload + + +class PayoutPayload(HalfBlockPayload): + + format_list = HalfBlockPayload.format_list + ["I", "I"] + + def __init__(self, public_key, sequence_number, link_public_key, link_sequence_number, previous_hash, + signature, transaction, circuit_id, base_amount): + super(PayoutPayload, self).__init__(public_key, sequence_number, link_public_key, link_sequence_number, + previous_hash, signature, transaction) + self.circuit_id = circuit_id + self.base_amount = base_amount + + @classmethod + def from_half_block(cls, block, circuit_id, base_amount): + return PayoutPayload( + block.public_key, + block.sequence_number, + block.link_public_key, + block.link_sequence_number, + block.previous_hash, + block.signature, + block.transaction, + circuit_id, + base_amount + ) + + def to_pack_list(self): + data = super(PayoutPayload, self).to_pack_list() + data.append(('I', self.circuit_id)) + data.append(('I', self.base_amount)) + return data + + @classmethod + def from_unpack_list(cls, *args): + return PayoutPayload(*args) From c136bd88bf0b091bf64ed3804f7306cfa4ff9b96 Mon Sep 17 00:00:00 2001 From: Martijn de Vos Date: Sun, 4 Mar 2018 16:18:21 +0100 Subject: [PATCH 2/3] Updated IPv8 pointer --- Tribler/pyipv8 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tribler/pyipv8 b/Tribler/pyipv8 index ac759620112..9e417ab2643 160000 --- a/Tribler/pyipv8 +++ b/Tribler/pyipv8 @@ -1 +1 @@ -Subproject commit ac759620112721eaa42c86037f40d3951bdbbf78 +Subproject commit 9e417ab2643a7f6782bf73bc35644fb4350b33ba From 2bec07bc5e1f35acda4142b299c1cfd062e3def5 Mon Sep 17 00:00:00 2001 From: Martijn de Vos Date: Sun, 4 Mar 2018 16:52:57 +0100 Subject: [PATCH 3/3] Increased market tests timeout --- Tribler/Test/Community/Market/test_community.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Tribler/Test/Community/Market/test_community.py b/Tribler/Test/Community/Market/test_community.py index cedd09b4beb..994bfab3c74 100644 --- a/Tribler/Test/Community/Market/test_community.py +++ b/Tribler/Test/Community/Market/test_community.py @@ -116,12 +116,12 @@ def test_counter_trade(self): order = self.nodes[0].overlay.create_ask(2, 'DUM1', 2, 'DUM2', 3600) order._traded_quantity._quantity = 1 # Partially fulfill this order - yield self.deliver_messages(timeout=.2) + yield self.deliver_messages(timeout=.4) self.assertEqual(len(self.nodes[2].overlay.order_book.asks), 1) self.nodes[1].overlay.create_bid(2, 'DUM1', 2, 'DUM2', 3600) - yield self.deliver_messages(timeout=.2) + yield self.deliver_messages(timeout=.4) self.assertTrue(self.nodes[0].overlay.transaction_manager.find_all()) self.assertTrue(self.nodes[1].overlay.transaction_manager.find_all()) @@ -136,7 +136,7 @@ def test_e2e_trade(self): self.nodes[0].overlay.create_ask(1, 'DUM1', 1, 'DUM2', 3600) self.nodes[1].overlay.create_bid(1, 'DUM1', 1, 'DUM2', 3600) - yield self.deliver_messages(timeout=.2) + yield self.deliver_messages(timeout=.5) # Compute reputation self.nodes[0].overlay.compute_reputation() @@ -164,7 +164,7 @@ def test_cancel(self): ask_order = self.nodes[0].overlay.create_ask(1, 'DUM1', 1, 'DUM2', 3600) - yield self.deliver_messages(timeout=.2) + yield self.deliver_messages(timeout=.4) self.nodes[0].overlay.cancel_order(ask_order.order_id) @@ -186,7 +186,7 @@ def test_failing_payment(self): self.nodes[0].overlay.create_ask(1, 'DUM1', 1, 'DUM2', 3600) self.nodes[1].overlay.create_bid(1, 'DUM1', 1, 'DUM2', 3600) - yield self.deliver_messages(timeout=.2) + yield self.deliver_messages(timeout=.4) self.assertEqual(self.nodes[0].overlay.transaction_manager.find_all()[0].status, "error") self.assertEqual(self.nodes[1].overlay.transaction_manager.find_all()[0].status, "error") @@ -205,7 +205,7 @@ def test_e2e_trade(self): self.nodes[0].overlay.create_ask(1, 'DUM1', 1, 'DUM2', 3600) self.nodes[1].overlay.create_bid(1, 'DUM1', 1, 'DUM2', 3600) - yield self.deliver_messages(timeout=.2) + yield self.deliver_messages(timeout=.5) # Verify that the trade has been made self.assertTrue(self.nodes[0].overlay.transaction_manager.find_all())