Skip to content

Commit 4f4c96b

Browse files
committed
chore: update usage doc and testing
1 parent 0ead8d8 commit 4f4c96b

File tree

2 files changed

+209
-7
lines changed

2 files changed

+209
-7
lines changed
Lines changed: 169 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,169 @@
1-
# Testing Multi-node Blueprints
1+
# Testing Multi-node Blueprints
2+
3+
This guide explains how to test blueprints that require multiple nodes for distributed computation, such as threshold cryptography protocols or consensus protocols. We'll walk through setting up a test environment and running multi-node tests using our SDK's testing utilities.
4+
5+
## Overview
6+
7+
When developing multi-node blueprints, testing requires simulating a network of nodes that can communicate and coordinate with each other. Our SDK provides testing utilities that make it easy to:
8+
9+
- Set up a simulated multi-node network environment
10+
- Configure individual nodes with custom handlers
11+
- Submit jobs and verify results across nodes
12+
- Test distributed protocols and consensus mechanisms
13+
14+
## Test Environment Setup
15+
16+
### Prerequisites
17+
18+
First, include the necessary testing utilities in your project:
19+
20+
```rust
21+
use blueprint_sdk::testing::utils::tangle::TangleTestHarness;
22+
use blueprint_sdk::testing::utils::harness::TestHarness;
23+
use blueprint_sdk::testing::tempfile;
24+
use blueprint_sdk::logging;
25+
```
26+
27+
### Basic Setup
28+
29+
1. **Initialize Logging and Error Handling**:
30+
31+
```rust
32+
logging::setup_log();
33+
```
34+
35+
2. **Create Test Harness**:
36+
37+
```rust
38+
let tmp_dir = tempfile::TempDir::new()?;
39+
let harness = TangleTestHarness::setup(tmp_dir).await?
40+
```
41+
42+
## Setting Up Multi-node Services
43+
44+
### Node Configuration
45+
46+
1. **Initialize Test Environment**:
47+
48+
```rust
49+
// N specifies number of nodes (e.g. N = 3)
50+
let (mut test_env, service_id, blueprint_id) = harness.setup_services::<N>(false).await?;
51+
test_env.initialize().await?;
52+
```
53+
54+
2. **Configure Individual Nodes**:
55+
56+
```rust
57+
let handles = test_env.node_handles().await;
58+
for handle in handles {
59+
// Get node configuration
60+
let config = handle.gadget_config().await;
61+
// Initialize node-specific context
62+
let blueprint_ctx = YourContext::new(config.clone()).await?;
63+
// Add job handlers
64+
let job_handler = YourJobHandler::new(&config, blueprint_ctx.clone()).await?;
65+
handle.add_job(job_handler).await;
66+
}
67+
```
68+
69+
3. **Allow Time for Network Setup**:
70+
71+
```rust
72+
// Wait for network handshakes
73+
tokio::time::sleep(std::time::Duration::from_secs(10)).await;
74+
```
75+
76+
4. **Start the Environment**:
77+
78+
```rust
79+
test_env.start().await?;
80+
```
81+
82+
## Running Tests
83+
84+
### Submitting Jobs
85+
86+
To test your blueprint's functionality, submit jobs and verify their results:
87+
88+
```rust
89+
// Submit a job with arguments
90+
let job = harness
91+
.submit_job(
92+
service_id,
93+
JOB_ID,
94+
vec![InputValue::Uint16(2)] // Example job argument
95+
)
96+
.await?;
97+
logging::info!("Submitted job {JOB_ID} with service ID {service_id}");
98+
```
99+
100+
### Verifying Results
101+
102+
Wait for job completion and verify the results:
103+
104+
```rust
105+
// Wait for job execution
106+
let results = harness.wait_for_job_execution(service_id, job).await?;
107+
assert_eq!(results.service_id, service_id);
108+
109+
// Verify outputs
110+
if !expected_outputs.is_empty() {
111+
assert_eq!(
112+
results.result.len(),
113+
expected_outputs.len(),
114+
"Number of outputs doesn't match expected"
115+
);
116+
117+
// Add more verification logic as needed...
118+
}
119+
```
120+
121+
## Best Practices
122+
123+
1. **Error Handling**: Always implement proper error handling and logging to diagnose test failures.
124+
125+
2. **Network Delays**: Include appropriate delays for network initialization and handshakes.
126+
127+
3. **Verification**: Thoroughly verify all job outputs against expected results.
128+
129+
4. **Cleanup**: Use temporary directories that are automatically cleaned up after tests.
130+
131+
5. **Logging**: Implement comprehensive logging to track test progress and debug issues.
132+
133+
## Example: Complete Test Structure
134+
135+
Here's a complete example showing how to structure a multi-node test:
136+
137+
```rust
138+
#[tokio::test(flavor = "multi_thread")]
139+
async fn test_blueprint() -> color_eyre::Result<()> {
140+
logging::setup_log();
141+
let tmp_dir = tempfile::TempDir::new()?;
142+
let harness = TangleTestHarness::setup(tmp_dir).await?;
143+
144+
// Initialize nodes
145+
let (mut test_env, service_id, ) = harness.setup_services::<3>(false).await?;
146+
test_env.initialize().await?;
147+
148+
// Configure nodes
149+
let handles = test_env.node_handles().await;
150+
for handle in handles {
151+
// Add handlers
152+
// ...
153+
}
154+
155+
// Wait for network setup
156+
tokio::time::sleep(std::time::Duration::from_secs(10)).await;
157+
test_env.start().await?;
158+
159+
// Run test jobs
160+
let job = harness.submit_job(service_id, JOB_ID, vec![/ args /]).await?;
161+
let results = harness.wait_for_job_execution(service_id, job).await?;
162+
163+
// Verify results
164+
assert_eq!(results.service_id, service_id);
165+
166+
// Additional verification...
167+
Ok(())
168+
}
169+
```

pages/developers/p2p-networking/usage.mdx

Lines changed: 40 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,46 @@ fn example_usage(config: GadgetConfiguration) -> Result<(), GadgetError> {
2222
let network_handle = config.libp2p_start_network(network_config, allowed_keys)?;
2323

2424
// 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(/* ... */);
25+
loop {
26+
if let Some(msg) = network_handle.next_protocol_message() {
27+
println!("Received message: {:?}", msg);
28+
}
2729

28-
// Receive gossip messages from the network
29-
// Send gossip messages to the network
30-
network_handle.send_gossip_message(/* ... */);
30+
tokio::time::sleep(std::time::Duration::from_millis(100)).await;
31+
}
3132

33+
// Use the handle to send p2p messages to the network
34+
let p2p_routing = MessageRouting {
35+
/// Unique identifier for this message
36+
message_id: 1,
37+
/// The round/sequence number this message belongs to
38+
round_id: 1,
39+
/// The sender's information
40+
sender: ParticipantInfo {
41+
/// The public key of the sender
42+
public_key: InstanceMsgPublicKey(/* ... */),
43+
/// The address of the sender
44+
address: /* ... */
45+
},
46+
/// Recipient information for direct messages
47+
recipient: Some(ParticipantInfo {
48+
public_key: InstanceMsgPublicKey(/* ... */),
49+
address: /* ... */
50+
}),
51+
};
52+
network_handle.send(p2p_routing, /* ...some bytes (Vec<u8>)... */);
3253

54+
// Send gossip messages to the network
55+
let gossip_routing = MessageRouting {
56+
message_id: 1,
57+
round_id: 1,
58+
sender: ParticipantInfo {
59+
public_key: InstanceMsgPublicKey(/* ... */),
60+
address: /* ... */
61+
},
62+
recipient: None,
63+
};
64+
network_handle.send(gossip_routing, /* ...some bytes (Vec<u8>)... */);
3365

3466
Ok(())
3567
}
@@ -95,7 +127,9 @@ impl BlsContext {
95127

96128
### Round Based Job
97129

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`
130+
`round-based` is a [library for building structure round based protocols](https://github.com/LFDT-Lockness/round-based), especially MPC protocols. There are a variety of benefits to structuring your protocol in this way and it can streamline the separation between networking and protocol logic.
131+
132+
To leverage a `round-based` protocol that handles sending, receiving, and processing messages use the `RoundBasedNetworkAdapter` available from the SDK and in the `gadget-networking-round-based-extension` crate.
99133

100134
```rust
101135
#[job(

0 commit comments

Comments
 (0)