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

Subscription filter #1210

Merged
merged 327 commits into from Sep 25, 2021
Merged

Subscription filter #1210

merged 327 commits into from Sep 25, 2021

Conversation

synzhu
Copy link
Contributor

@synzhu synzhu commented Aug 26, 2021

Implements subscription filter. Will not work 100% until libp2p/go-libp2p-pubsub#449 is fixed.

https://github.com/dapperlabs/flow-go/issues/5801

synzhu and others added 30 commits August 20, 2021 19:32
network/p2p/subscription_filter.go Outdated Show resolved Hide resolved
engine/channels.go Show resolved Hide resolved
Copy link
Contributor

@huitseeker huitseeker left a comment

Choose a reason for hiding this comment

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

This code LGTM.

@smnzhu there's a CI unit test failure on TestCommandRunner that results in a nil dereference. Is there any chance you'd have time to look into it? My hunch is the cleanup / shutdown of the admin server might run first while leaving pending command, so that they probably hit a cleaned up (nil) runner in the end.

@yhassanzadeh13 yhassanzadeh13 self-assigned this Sep 22, 2021
@huitseeker huitseeker mentioned this pull request Sep 22, 2021
engine/channels.go Outdated Show resolved Hide resolved
engine/channels.go Outdated Show resolved Hide resolved
Copy link
Contributor

@yhassanzadeh13 yhassanzadeh13 left a comment

Choose a reason for hiding this comment

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

Overall clean and neat, just a few comments to preserve the extensibility.

Also, on a separate note, I could not find implementation accounting for https://github.com/dapperlabs/flow-go/issues/5861 in this PR. That is fine, but just wanted to make sure https://github.com/dapperlabs/flow-go/issues/5861 is not a duplicate.
Basically, the subscription filter does not prevent an engine to wrongfully subscribe to a topic that it is not supposed to do, e.g., a consensus node can try registering itself on request-chunks. The aim of https://github.com/dapperlabs/flow-go/issues/5861 is to prevent such scenarios that arising of channelRoleMap getting out of sync or distorted and seems https://github.com/dapperlabs/flow-go/issues/5861 and this PR are serving quite orthogonal purposes. I would be happy to take https://github.com/dapperlabs/flow-go/issues/5861 and apply a fix.

// replaces channel with the stripped-off prefix
channel = clusterChannel
if _, isCluster := ClusterChannel(channel); isCluster {
return ClusterChannelRoles(), true
Copy link
Contributor

Choose a reason for hiding this comment

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

I like the general idea of defining these filter functions (e.g., ClusterChannelRoles), however, I would still recommend keeping the information-centric architecture, i.e., having channelRoleMap as the source-of-truth and then defining these filter functions on top of it, e.g.,

func ClusterChannelRoles() flow.RoleList {
	clusterRoles := flow.RoleList{}
	for channel, roles := range channelRoleMap{
		if _, ok := ClusterChannel(channel); ok{
			clusterRoles.Union(roles)
		}
	}
	
	return clusterRoles
}

By keeping the design information-centric around channelRoleMap instead of ad-hoc functions with hard-coded parameters, we preserve the safety of extensibility in a longer-term outlook.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

right, but channelRoleMap doesn't make sense for cluster-based channels imo because they are unique to the chain ID. ie, the value stored in channelRoleMap is not actually a "real" channel

Copy link
Contributor Author

@synzhu synzhu Sep 24, 2021

Choose a reason for hiding this comment

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

I think the real solution is to remove ChannelSyncCluster() and ChannelConsensusCluster entirely, and simply redefine TopicFromChannel to take in a chain ID in addition to a RootBlockID instead. Or to go even further, we can define a closure or a struct ChannelToTopicConverter which does the conversions.

Then we'd be able to rename syncClusterPrefix to simply SyncCluster (similary for consensus) and add it to the channel role map.

// non-cluster channel deduplicated based identifier of role list
if _, cluster := ClusterChannel(channel); !cluster {
id := channelRoleMap[channel].ID()
Copy link
Contributor

Choose a reason for hiding this comment

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

ID() method is quite resource-heavy, and that is why we kept it out of the loop there. I could not find any reason we need to recompute it over each iteration. If that is the case, please move it to its old place out of the loop.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The old place is already inside the loop 🧐

I have only placed it inside the if, which is only saving computation because it will be computed less often.

return network.ChannelList{
UnstakedSyncCommittee,
PublicSyncCommittee,
Copy link
Contributor

Choose a reason for hiding this comment

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

Similar to my earlier comment about keeping channelRoleMap as the source of truth, I would suggest not to hard code these in the body of functions. Instead, we can have a naming convention that all channels starting with public are public channels, and then do:

// all public channels should start with "public-" prefix.
const publicChannelPrefix = "public-"

// PublicChannels returns all channels that on the public network.
func PublicChannels() network.ChannelList {
	publicChannels := network.ChannelList{}
	for channel := range channelRoleMap {
		if strings.HasPrefix(channel.String(), publicChannelPrefix) {
			publicChannels = append(publicChannels, channel)
		}
	}
	return publicChannels
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Imo, channelRoleMap is only relevant to the channels where roles matter, ie private channels.

Public channels can be joined by anyone, regardless of role (and even unstaked nodes who don't have a role whatsoever), so I think it makes sense to treat them separately here.

network/p2p/middleware.go Show resolved Hide resolved
network/p2p/sporking_test.go Outdated Show resolved Hide resolved
network/p2p/libp2pNode.go Outdated Show resolved Hide resolved
network/p2p/test_utils.go Outdated Show resolved Hide resolved
network/p2p/subscription_filter_test.go Show resolved Hide resolved
network/p2p/subscription_filter_test.go Outdated Show resolved Hide resolved
}
}

func (f *RoleBasedFilter) allowedTopics(pid peer.ID) map[network.Topic]struct{} {
Copy link
Contributor

Choose a reason for hiding this comment

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

shouldn't we have two different filter. One which all the staked node use and one which the full observer node uses and the Staked AN that support the observer node use?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We could do this, the at a high level, the logic for the subscription filter goes:

A node should only be allowed to subscribe to some set of channels based on its role.

This general rule is the same for any node type, so we can implement the exact same logic for all of them

Copy link
Contributor

@vishalchangrani vishalchangrani left a comment

Choose a reason for hiding this comment

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

some nits and a question but otherwise lgtm

@synzhu
Copy link
Contributor Author

synzhu commented Sep 24, 2021

Overall clean and neat, just a few comments to preserve the extensibility.

Also, on a separate note, I could not find implementation accounting for dapperlabs/flow-go#5861 in this PR. That is fine, but just wanted to make sure dapperlabs/flow-go#5861 is not a duplicate.
Basically, the subscription filter does not prevent an engine to wrongfully subscribe to a topic that it is not supposed to do, e.g., a consensus node can try registering itself on request-chunks. The aim of dapperlabs/flow-go#5861 is to prevent such scenarios that arising of channelRoleMap getting out of sync or distorted and seems dapperlabs/flow-go#5861 and this PR are serving quite orthogonal purposes. I would be happy to take dapperlabs/flow-go#5861 and apply a fix.

So originally, I never suggested that dapperlabs/flow-go#5861 is a duplicate, but actually I would like to clarify that the subscription filter does prevent an engine from wrongfully subscribing to a topic that it is not supposed to, in fact this is explicitly tested in the unit test.

It wasn't clear to me based on the wording what exactly the goal of dapperlabs/flow-go#5861 was, but if the goal is to ensure that nodes only subscribe to the appropriate channels based on their role, then the subscription filter does ensure this.

@synzhu
Copy link
Contributor Author

synzhu commented Sep 24, 2021

bors merge

bors bot added a commit that referenced this pull request Sep 24, 2021
1210: Subscription filter r=smnzhu a=smnzhu

Implements subscription filter. Will not work 100% until libp2p/go-libp2p-pubsub#449 is fixed.

https://github.com/dapperlabs/flow-go/issues/5801

Co-authored-by: Simon Zhu <simon.zsiyan@gmail.com>
Co-authored-by: vishal <1117327+vishalchangrani@users.noreply.github.com>
@bors
Copy link
Contributor

bors bot commented Sep 24, 2021

Canceled.

@synzhu
Copy link
Contributor Author

synzhu commented Sep 25, 2021

bors merge

@bors
Copy link
Contributor

bors bot commented Sep 25, 2021

@bors bors bot merged commit 03cba83 into master Sep 25, 2021
@bors bors bot deleted the smnzhu/subscription-filter branch September 25, 2021 02:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants