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

Network Orchestrator service proposal #402

Merged
merged 32 commits into from
Jul 8, 2022

Conversation

leviathanbeak
Copy link
Contributor

Network Orchestrator is the service that:

  • holds and runs p2p service
  • holds multiple tokio::sync::mpsc::Sender values for propagating p2p messages to different components
  • holds and listens from tokio::sync::mpsc::Receiver to get messages from different fuel-core components

This initial version is (loosely) based on miro design.

Apart from general design I would need feedback on specific components

@adlerjohn adlerjohn added the enhancement New feature or request label Jun 11, 2022
fuel-p2p/src/orchestrator.rs Outdated Show resolved Hide resolved
fuel-p2p/src/orchestrator.rs Outdated Show resolved Hide resolved
fuel-p2p/src/orchestrator.rs Outdated Show resolved Hide resolved
pub async fn run(&mut self) {
loop {
tokio::select! {
p2p_event = self.p2p_service.next_event() => {
Copy link
Contributor

Choose a reason for hiding this comment

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

instead of nesting all these match patterns, maybe create a single level identity who will check the cases?

fuel-p2p/src/orchestrator.rs Outdated Show resolved Hide resolved
@leviathanbeak leviathanbeak force-pushed the leviathanbeak/p2p_orchestrator branch from 4e6a3bb to ad0577a Compare June 29, 2022 19:57
@leviathanbeak
Copy link
Contributor Author

Most of the reasoning for these changes can be found at: https://fuellabs.slack.com/archives/C01L1HUJSL8/p1656343694067609

It could be argued that it's a bit over-engineered but on the flip side we do not .clone() any values from Arc<T> that we receive/send so it is definitely cleaner and more performant in that regard.

@leviathanbeak leviathanbeak requested review from rakita and Voxelot June 29, 2022 20:19
@leviathanbeak leviathanbeak requested a review from vlopes11 June 29, 2022 20:19
@leviathanbeak leviathanbeak marked this pull request as ready for review July 1, 2022 19:28
rakita
rakita previously approved these changes Jul 6, 2022
Copy link
Contributor

@rakita rakita left a comment

Choose a reason for hiding this comment

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

tbh it is hard to do indepth review without knowing libp2p lib. Reviewing the code it looked good so I am okay to approve it.
I think a few things will pop out when starting to integrate p2p with the rest of the system. In wiki It was hard to specify everything in one go here so i see there is inconsistencies as block producer broadcasts block (it is used by multiple parties) but p2p has mpsc that wants to receive it.


db: Arc<dyn RelayerDb>,

outbound_responses: FuturesUnordered<ResponseFuture>,
Copy link
Contributor

Choose a reason for hiding this comment

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

Didn't know about this, nice :)

tx_transaction: Sender<TransactionBroadcast>,
tx_block: Sender<BlockBroadcast>,

db: Arc<dyn RelayerDb>,
Copy link
Contributor

Choose a reason for hiding this comment

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

[nit] You can define yourown db trait in fuel-core-interface and implement it inside fuel-core. Leave if for future work

@@ -16,15 +17,18 @@ pub enum BlockBroadcast {
NewBlock(FuelBlock),
}

pub enum P2pMpsc {
pub enum P2PRequestEvent {
Copy link
Member

@Voxelot Voxelot Jul 6, 2022

Choose a reason for hiding this comment

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

[nit] Camel-casing applies to acronyms as well (P2P -> P2p):

In UpperCamelCase, acronyms and contractions of compound words count as one word: use Uuid rather than UUID, Usize rather than USize or Stdin rather than StdIn
https://rust-lang.github.io/api-guidelines/naming.html

Suggested change
pub enum P2PRequestEvent {
pub enum P2pRequestEvent {

Copy link
Contributor Author

Choose a reason for hiding this comment

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

good point, but "P2p" feels so wrong 😬

} else {
debug!("ResponseChannel for {:?} does not exist!", request_id);
return Err(ResponseError::ResponseChannelDoesNotExist);
_ => {}
Copy link
Member

@Voxelot Voxelot Jul 6, 2022

Choose a reason for hiding this comment

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

Should we log anything in the event of an error?

Suggested change
_ => {}
(Err(e), _) => { debug!("unexpected error occurred while processing message response: {:?}", e); }

Copy link
Contributor Author

Choose a reason for hiding this comment

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

logged it, and added another error enum variant

Comment on lines 135 to 136


Copy link
Member

Choose a reason for hiding this comment

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

normally cargo fmt would trim this, but don't think it works inside of select! macros.

Suggested change

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 select! support is terrible


self.outbound_responses.push(
Box::pin(async move {
db.get_sealed_block(block_height).await.map(|block| (OutboundResponse::ResponseBlock(block), request_id))
Copy link
Member

@Voxelot Voxelot Jul 8, 2022

Choose a reason for hiding this comment

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

It may make sense in the future to have some other service/module handle fetching blocks from the DB for the orchestrator. For instance, if there are many outstanding requests (e.g. lots of full-syncs) having a dedicated block-fetching worker on the spawn_blocking threadpool would help avoid stalling the main async runtime.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

since the fetching itself is already async, shouldn't it be just fine to spawn another async task with tokio::spawn instead ?

Copy link
Member

@Voxelot Voxelot Jul 8, 2022

Choose a reason for hiding this comment

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

good point, it should be the responsibility of this async-trait implementor to deal with any potential blocking issues. A regular spawn doesn't really net us anything here since that's more for launching background tasks that don't have an active poller.


/// Given a `GossipsubBroadcastRequest` retruns a `GossipTopic`
/// which is broadcast over the network with the serialized inner value of `GossipsubBroadcastRequest`
pub fn get_gossipsub_topic(&self, outgoing_request: &GossipsubBroadcastRequest) -> GossipTopic {
Copy link
Member

Choose a reason for hiding this comment

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

Do we have tests to verify all of these lookups and topic encodings are accurate? Since topic setup relies on manual string formatting and setup, it will be harder for the compiler to detect errors during refactoring etc.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

good observation, added a test that checks all the options

@@ -412,8 +416,8 @@ mod tests {
// verifies that we've got at least a single peer address to send message to
if !peer_addresses.is_empty() && !message_sent {
message_sent = true;
let default_tx = FuelGossipsubMessage::NewTx(Transaction::default());
node_a.publish_message(selected_topic.clone(), default_tx).unwrap();
let default_tx = GossipsubBroadcastRequest::NewTx(Arc::new(Transaction::default()));
Copy link
Member

Choose a reason for hiding this comment

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

We should also have tests that ensure message routing and serialization work as expected across all network event types we have. Currently, it seems like we only exercise the NewTx and RequestBlock code paths in our tests.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

added tests for all Gossipsub Messages, as for Request-Response, currently we only support RequestBlock anyway

@Voxelot
Copy link
Member

Voxelot commented Jul 8, 2022

ready to approve once test coverage for new message types is improved.

@leviathanbeak
Copy link
Contributor Author

leviathanbeak commented Jul 8, 2022

did some additional cleaning:

  • removed unwrap() when initializing the Orchestrator::new()
  • removed some unused methods
  • only made public the Orchestrator and what is needed for it to start


#[tokio::test]
#[instrument]
async fn gossipsub_broadcast_vote() {
Copy link
Member

Choose a reason for hiding this comment

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

I like these granular clean looking tests

@Voxelot
Copy link
Member

Voxelot commented Jul 8, 2022

LGTM! Good improvements with the test coverage

@leviathanbeak leviathanbeak merged commit 6ea571e into master Jul 8, 2022
@leviathanbeak leviathanbeak deleted the leviathanbeak/p2p_orchestrator branch July 8, 2022 19:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
Archived in project
Development

Successfully merging this pull request may close these issues.

5 participants