Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce "default init" and "unload" methods for Ipv8Component #6402

Merged
merged 2 commits into from
Oct 5, 2021

Conversation

drew2a
Copy link
Contributor

@drew2a drew2a commented Oct 1, 2021

Based on #6396

class Ipv8Component(RestfulComponent):
    ipv8: IPv8

    def initialise_community_by_default(self, community):
        community.bootstrappers.append(self.make_bootstrapper())

        # Value of `target_peers` must not be equal to the value of `max_peers` for this community.
        # This causes a deformed network topology and makes it harder for peers to connect to others.
        # More information: https://github.com/Tribler/py-ipv8/issues/979#issuecomment-896643760
        random_walk_max_peers = max(10, community.max_peers - 10)
        self.ipv8.add_strategy(community, RandomWalk(community), random_walk_max_peers)

    async def unload_community(self, community):
        await self.ipv8.unload_overlay(community)

@drew2a drew2a force-pushed the fix/ipv8_community_bootstrapper branch 2 times, most recently from 4f05665 to fd8cf86 Compare October 1, 2021 12:52
@drew2a drew2a changed the title Introduce default init and unload methods Introduce "default init" and "unload" methods for Ipv8Component Oct 1, 2021
@drew2a drew2a force-pushed the fix/ipv8_community_bootstrapper branch 2 times, most recently from bc9b0b8 to 99beb20 Compare October 1, 2021 18:25
@drew2a drew2a marked this pull request as ready for review October 1, 2021 18:37
@drew2a drew2a requested review from a team, kozlovsky and qstokkink and removed request for a team and kozlovsky October 1, 2021 18:37
qstokkink
qstokkink previously approved these changes Oct 2, 2021
Copy link
Contributor

@qstokkink qstokkink left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice 👍

In my opinion this is good to merge as-is. However, I would urge you to consider implementing my one suggestion already in this PR.

ipv8 = self.ipv8
community = DiscoveryCommunity(self.peer, ipv8.endpoint, ipv8.network, max_peers=100)
community.bootstrappers.append(self.make_bootstrapper())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: seems like you can replace this with self.initialise_community_by_default(community) and also shed the ipv8.add_strategy(community, RandomWalk(community), 20).
Same for _init_dht_discovery_community. Loses 2 LOC overall.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree. Is 20 target peers is necessary for the RandomWalk strategy for DiscoveryCommunity?

Why I asking is because if I replace it by self.initialise_community_by_default(community), then target_peers become max_peers-10 == 90

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Short answer: yes, 20 is a good idea.

Long answer: The DiscoveryCommunity is a meta-community that all peers join to quickly synchronize the other Communities they are a part of. This also forms a secondary bootstrap mechanism (which is why you generally don't want to deviate from the default parameterization of your Community and use a custom Network()). Actively walking to some peers in the DiscoveryCommunity will allow you to get a little bit of diversity in your connections. However, walking to too many peers here will just give you a lot of peers you do not share Communities with. 20 seems to be a good number (also considering the network topologies of the other Communities this Community shares its peer pool with). You could even set this to 0. However, 90 may produce too many open connections if overlay identifiers start diverging in the network.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got it. What if we will rewrite initialise_community_by_default this way:

    def initialise_community_by_default(self, community, default_random_walk_max_peers=20):
        community.bootstrappers.append(self.make_bootstrapper())

        # Value of `target_peers` must not be equal to the value of `max_peers` for the community.
        # This causes a deformed network topology and makes it harder for peers to connect to others.
        # More information: https://github.com/Tribler/py-ipv8/issues/979#issuecomment-896643760
        #
        # Then:
        # random_walk_max_peers should be less than community.max_peers:
        random_walk_max_peers = min(default_random_walk_max_peers, community.max_peers - 10)

        # random_walk_max_peers should be greater than 0
        random_walk_max_peers = max(0, random_walk_max_peers)
        self.ipv8.add_strategy(community, RandomWalk(community), random_walk_max_peers)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems good to me 👍

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Implemented

database = BandwidthDatabase(database_path, self._ipv8_component.peer.public_key.key_to_bin())
self.community = bandwidth_cls(self._ipv8_component.peer,
self._ipv8_component.ipv8.endpoint,
self._ipv8_component.ipv8.network,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thought/nit: We're injecting self._ipv8_component.ipv8.network as a dependency and then the component itself is overwriting its input with a Network() of its own creation. We should, at some point (probably not this PR) move the Network() overwrite to this file (same for PopularityCommunity).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, probably. For me purpose of overwriting a Network is unclear.
It is true for PopularityCommunity and GigachannelCommunity (as successors of RemoteQueryCommunity)
cc: @ichorid

(I see it as out of the scope of this PR)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

GigaChannelCommunity walks and deletes peers aggressively, so creates a separate Network instance to prevent interfering with other communities.

Copy link
Contributor

@qstokkink qstokkink Oct 4, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The reason for a "clean" Network() is the introduction of bias through custom parameterization of Communities. If you bias your peer discovery mechanism, you get a self-reinforcing effect that essentially forces some peers out of your network. It is not a problem if one peer deviates, but if you force a default on the entire network you will start seeing this. We've learned this the hard way #2894 (comment) (yes, we sinkhole attacked our own network) Therefore, for every Community that uses custom walks (including peer removal) or custom parameterization, we use a new Network.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Implemented here: #6408

Comment on lines 66 to 87
# test dht disabled
tribler_config.dht.enabled = True
session = Session(tribler_config, [MasterKeyComponent(), RESTComponent(), Ipv8Component()])
with session:
await session.start()

comp = Ipv8Component.instance()
assert comp.dht_discovery_community

# test discovery_community enabled
tribler_config.gui_test_mode = False
tribler_config.discovery_community.enabled = True
session = Session(tribler_config, [MasterKeyComponent(), RESTComponent(), Ipv8Component()])
with session:
await session.start()

comp = Ipv8Component.instance()
assert comp._peer_discovery_community
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: This test now breaks with the Arrange/Act/Assert pattern: what I see here is Arrange/Assert/Arrange/Assert/Arrange/Assert. By splitting this code at the comments (turning # test dht disabled into async def test_ipv8_component_dht_disabled() and # test discovery_community enabled into async def test_ipv8_component_discovery_enabled()) you can follow the AAA pattern with very little effort.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree! Will implement it soon.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Implemented

@drew2a drew2a force-pushed the fix/ipv8_community_bootstrapper branch from 99beb20 to 8daf601 Compare October 5, 2021 09:27
@sonarqubecloud
Copy link

sonarqubecloud bot commented Oct 5, 2021

Kudos, SonarCloud Quality Gate passed!    Quality Gate passed

Bug A 0 Bugs
Vulnerability A 0 Vulnerabilities
Security Hotspot A 0 Security Hotspots
Code Smell A 0 Code Smells

No Coverage information No Coverage information
No Duplication information No Duplication information

Copy link
Contributor

@qstokkink qstokkink left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

praise: Thanks for going out of your way to even implement the nit and optional suggestion. Looks good 👍

@drew2a drew2a merged commit 8263c60 into Tribler:main Oct 5, 2021
@drew2a drew2a deleted the fix/ipv8_community_bootstrapper branch October 5, 2021 10:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

3 participants