|
2 | 2 |
|
3 | 3 | To spin up a P2P network, following two methods are provided on `GadgetConfiguration`:
|
4 | 4 |
|
5 |
| -* `GadgetConfiguration::libp2p_network_config()` |
6 |
| -* `GadgetConfiguration::libp2p_start_network()` |
| 5 | +- `GadgetConfiguration::libp2p_network_config()` |
| 6 | +- `GadgetConfiguration::libp2p_start_network()` |
| 7 | + |
| 8 | +## Example |
| 9 | + |
| 10 | +Here's an example of how to spin up a P2P network and send messages to it. |
7 | 11 |
|
8 | 12 | ```rust
|
9 | 13 | use blueprint_sdk::networking::service_handle::NetworkServiceHandle;
|
10 | 14 | use blueprint_sdk::networking::InstanceMsgPublicKey;
|
11 |
| -use blueprint_sdk::macros::contexts::TangleClientContext; |
| 15 | +fn example_usage(config: GadgetConfiguration) -> Result<(), GadgetError> { |
| 16 | + let allowed_keys: HashSet<InstanceMsgPublicKey> = /* ... */; |
| 17 | + |
| 18 | + // Create the `NetworkConfig` based on the `GadgetConfiguration` |
| 19 | + let network_config = config.libp2p_network_config("my/protocol/1.0.0")?; |
| 20 | + |
| 21 | + // Start up the network, getting a handle back |
| 22 | + let network_handle = config.libp2p_start_network(network_config, allowed_keys)?; |
| 23 | + |
| 24 | + // Use the handle to receive p2p messages from the network |
| 25 | + // Use the handle to send p2p messages to the network |
| 26 | + network_handle.send_message(/* ... */); |
| 27 | + |
| 28 | + // Receive gossip messages from the network |
| 29 | + // Send gossip messages to the network |
| 30 | + network_handle.send_gossip_message(/* ... */); |
| 31 | + |
| 32 | + |
| 33 | + |
| 34 | + Ok(()) |
| 35 | +} |
| 36 | +``` |
| 37 | + |
| 38 | +## Integrating Networking with Service contexts |
| 39 | + |
| 40 | +The P2P networking utilities can be integrated into service contexts to manage network state and handle messages. It exposes an interface for you to send messages to other peers of your service as well as gossip messages to the entire network of service instance operators. |
| 41 | + |
| 42 | +## Context Constructor |
| 43 | + |
| 44 | +Create a context that you can pass into your jobs and background services. |
| 45 | + |
| 46 | +```rust |
| 47 | +/// The context holds necessary information for the service to run. |
| 48 | +#[derive(Clone, KeystoreContext, TangleClientContext, ServicesContext)] |
| 49 | +pub struct BlsContext { |
| 50 | + #[config] |
| 51 | + pub config: GadgetConfiguration, |
| 52 | + #[call_id] |
| 53 | + pub call_id: Option<u64>, |
| 54 | + pub network_backend: NetworkServiceHandle, |
| 55 | + pub store: Arc<LocalDatabase<BlsState>>, |
| 56 | + pub identity: sp_core::ecdsa::Pair, |
| 57 | +} |
| 58 | + |
| 59 | +// Core context management implementation |
| 60 | +impl BlsContext { |
| 61 | + /// Creates a new service context with the provided configuration |
| 62 | + /// |
| 63 | + /// # Errors |
| 64 | + /// Returns an error if: |
| 65 | + /// - Network initialization fails |
| 66 | + /// - Configuration is invalid |
| 67 | + pub async fn new(config: GadgetConfiguration) -> Result<Self> { |
| 68 | + let operator_keys: HashSet<InstanceMsgPublicKey> = config |
| 69 | + .tangle_client() |
| 70 | + .await? |
| 71 | + .get_operators() |
| 72 | + .await? |
| 73 | + .values() |
| 74 | + .map(|key| InstanceMsgPublicKey(*key)) |
| 75 | + .collect(); |
| 76 | + |
| 77 | + let network_config = config.libp2p_network_config(NETWORK_PROTOCOL)?; |
| 78 | + let identity = network_config.instance_key_pair.0.clone(); |
| 79 | + |
| 80 | + let network_backend = config.libp2p_start_network(network_config, operator_keys)?; |
| 81 | + |
| 82 | + let keystore_dir = PathBuf::from(&config.keystore_uri).join("bls.json"); |
| 83 | + let store = Arc::new(LocalDatabase::open(keystore_dir)); |
| 84 | + |
| 85 | + Ok(Self { |
| 86 | + config, |
| 87 | + call_id: None, |
| 88 | + network_backend, |
| 89 | + store, |
| 90 | + identity, |
| 91 | + }) |
| 92 | + } |
| 93 | +} |
| 94 | +``` |
| 95 | + |
| 96 | +### Round Based Job |
| 97 | + |
| 98 | +In your job you can now leverage your `NetworkServiceHandle` to send messages to the network. You may also want to leverage a `round-based` protocol that handles sending, receiving, and processing messages with the `RoundBasedNetworkAdapter` |
| 99 | + |
| 100 | +```rust |
| 101 | +#[job( |
| 102 | + id = 0, |
| 103 | + params(t), |
| 104 | + event_listener( |
| 105 | + listener = TangleEventListener<BlsContext, JobCalled>, |
| 106 | + pre_processor = services_pre_processor, |
| 107 | + post_processor = services_post_processor, |
| 108 | + ), |
| 109 | +)] |
| 110 | +pub async fn keygen(t: u16, context: BlsContext) -> Result<Vec<u8>, GadgetError> { |
| 111 | + // Get configuration and compute deterministic values |
| 112 | + let blueprint_id = context |
| 113 | + .blueprint_id() |
| 114 | + .map_err(|e| KeygenError::ContextError(e.to_string()))?; |
| 115 | + let call_id = context |
| 116 | + .current_call_id() |
| 117 | + .await |
| 118 | + .map_err(|e| KeygenError::ContextError(e.to_string()))?; |
| 119 | + // Setup party information |
| 120 | + let (i, operators) = context |
| 121 | + .get_party_index_and_operators() |
| 122 | + .await |
| 123 | + .map_err(|e| KeygenError::ContextError(e.to_string()))?; |
| 124 | + let parties: HashMap<u16, InstanceMsgPublicKey> = operators |
| 125 | + .into_iter() |
| 126 | + .enumerate() |
| 127 | + .map(|(j, (_, ecdsa))| (j as PartyIndex, InstanceMsgPublicKey(ecdsa))) |
| 128 | + .collect(); |
| 129 | + let n = parties.len() as u16; |
| 130 | + let i = i as u16; |
| 131 | + // Create a new round based network adapter |
| 132 | + let network = RoundBasedNetworkAdapter::<KeygenMsg>::new( |
| 133 | + context.network_backend.clone(), |
| 134 | + i, |
| 135 | + parties.clone(), |
| 136 | + crate::context::NETWORK_PROTOCOL, |
| 137 | + ); |
12 | 138 |
|
13 |
| -let allowed_keys: HashSet<InstanceMsgPublicKey> = /* ... */; |
| 139 | + // Create a new round based party |
| 140 | + let party = round_based::party::MpcParty::connected(network); |
14 | 141 |
|
15 |
| -// Create the `NetworkConfig` based on the `GadgetConfiguration` |
16 |
| -let network_config = config.libp2p_network_config("my/protocol/1.0.0")?; |
| 142 | + // Run the keygen protocol |
| 143 | + let output = crate::keygen_state_machine::bls_keygen_protocol(party, i, t, n, call_id).await?; |
17 | 144 |
|
18 |
| -// Start up the network, getting a handle back |
19 |
| -let network_handle = config.libp2p_start_network(network_config, allowed_keys)?; |
20 |
| -``` |
| 145 | + Ok(output) |
| 146 | +} |
| 147 | +``` |
0 commit comments