1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
// Copyright 2020 ChainSafe Systems
// SPDX-License-Identifier: Apache-2.0
//!
//! Implementation agnostic abstraction of networking
//! operations and the transition frontier for mina node(s).
//!
//! The goal of this module is to provide extensible traits to
//! support graphql and libp2p backend, etc. to power
//! both wasm node(s) that run in browser and cli node(s)
//! that run on x86-64 and arm-64 CPU(s). It also makes it easy to mock
//! the networking layer to unittest the [TransitionFrontier]
//!
pub mod naive_transition_frontier;
pub use naive_transition_frontier::*;
mod processor_impl;
#[cfg(target_arch = "wasm32")]
pub mod js;
use async_trait::async_trait;
use tokio::sync::{mpsc, RwLock};
/// Request struct for querying a block
pub struct QueryBlockRequest {
/// Height of the block
pub height: usize,
/// State hash of the block
pub state_hash: String,
}
/// This struct handles the blocks that are received from the
/// network and has the capability of interacting asynchronously
/// with the networking layer
///
/// TODO: Should this below to its own crate?
#[async_trait(?Send)]
pub trait TransitionFrontier {
/// Type that represents a block
type Block;
/// Adds a block that is received from networking layer.
/// The block could be either pushed by other peers or
/// the response of [QueryBlockRequest].
async fn add_block(&mut self, block: Self::Block) -> anyhow::Result<()>;
/// Sets the block requester for querying a block, e.g. parent of certain block
/// The responses will be recieved in a asynchronous way by the `add_block` API
fn set_block_requester(&mut self, sender: mpsc::Sender<QueryBlockRequest>);
}
/// abstraction of networking operations for
/// non-consensus mina node(s).
#[async_trait(?Send)]
pub trait NonConsensusNetworkingOps {
/// Type that represents a block
type Block;
/// Sets the block responder that sends the blocks to the [TransitionFrontier]
///
/// Note that it only assumes that new blocks are being pushed
/// from the network, to support polling with the graphql API(s),
/// there should be a separate long running function in the [NonConsensusNetworkingOps] impl
/// that is invoked or scheduled separately
fn set_block_responder(&mut self, sender: mpsc::Sender<Self::Block>);
/// Queries a block with its height and state hash
async fn query_block(&mut self, request: &QueryBlockRequest) -> anyhow::Result<()>;
}
/// This struct processes all the interactions and data exchanges
/// between the [NonConsensusNetworkingOps] and the [TransitionFrontier]
pub struct NetworkMessageProcessor<NetworkBlock, FrontierBlock, TF, NCOps>
where
TF: TransitionFrontier<Block = FrontierBlock>,
NCOps: NonConsensusNetworkingOps<Block = NetworkBlock>,
{
/// The [TransitionFrontier] instance
transition_frontier: RwLock<TF>,
/// The [NonConsensusNetworkingOps] instance
nonconsensus_ops: RwLock<NCOps>,
/// Block receiver
block_receiver: RwLock<mpsc::Receiver<NetworkBlock>>,
/// [QueryBlockRequest] receiver
query_block_request_receiver: RwLock<mpsc::Receiver<QueryBlockRequest>>,
}