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
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
|
//! Nodes under the identity layer (`transport::identity`): named by node IDs, found
//! through addresses (seeds, HELLO_REPLYs, the member list), and believed only once a
//! node proved itself at an address.
use std::time::Duration;
use serde_json::json;
use super::{Sim, read, sim_key, write};
use crate::identity::{self, NodeKey};
use crate::state::AppState;
use crate::swarm::bootstrap::Start;
use crate::swarm::members;
use crate::transport::identity::{WHO_LABEL, signed};
use crate::transport::{HeadsSummary, IdentityProof, Keepalive, ParsedMessage};
const SOON: Duration = Duration::from_secs(20);
async fn peers_are_node_ids(node: &AppState) {
for (peer, _) in node.peers_snapshot().await {
assert!(identity::is_node_id(&peer), "peer {peer}");
}
}
/// Seeds by name (resolved by the net) and by address; the third node finds the second
/// only through what the first lists in its HELLO_REPLY.
#[tokio::test(flavor = "multi_thread", worker_threads = 4)]
async fn nodes_are_their_node_ids() {
let sim = Sim::with_identity(51);
let a = sim.start("a", &[], Start::Genesis);
let b = sim.start("b", &["a"], Start::Join);
let c = sim.start("c", &["sim:a"], Start::Join);
sim.wait_ready(&[&a, &b, &c], SOON).await;
assert_eq!(a.local_id(), sim_key("a").id());
write(&b, "x", json!(1)).await;
sim.wait_converged(&[&a, &b, &c], SOON).await;
assert_eq!(read(&c, "x").await, Some(json!(1)));
for node in [&a, &b, &c] {
peers_are_node_ids(node).await;
}
let (b_id, c_id) = (b.local_id().to_owned(), c.local_id().to_owned());
let a = &a;
sim.wait_until(
"b and c are registered with their addresses",
SOON,
move || {
let (b_id, c_id) = (b_id.clone(), c_id.clone());
async move {
let replica = a.doc.read().await;
members::addresses(&replica.doc, &b_id) == ["sim:b"]
&& members::addresses(&replica.doc, &c_id) == ["sim:c"]
}
},
)
.await;
}
/// With two neighbours each, most pairs of six nodes never meet through seeds: they
/// find each other's addresses in the member list.
#[tokio::test(flavor = "multi_thread", worker_threads = 4)]
async fn members_find_each_other_through_the_member_list() {
let sim = Sim::with_identity(52);
let two = |config: &mut crate::node::NodeConfig| config.neighbours_k = 2;
let a = sim.start_with("a", &[], Start::Genesis, two);
let others: Vec<AppState> = ["b", "c", "d", "e", "f"]
.into_iter()
.map(|id| sim.start_with(id, &["a"], Start::Join, two))
.collect();
let mut all: Vec<&AppState> = vec![&a];
all.extend(others.iter());
sim.wait_ready(&all, SOON).await;
write(&others[4], "from/f", json!("f")).await;
write(&others[0], "from/b", json!("b")).await;
sim.wait_converged(&all, SOON).await;
for node in &all {
assert_eq!(read(node, "from/f").await, Some(json!("f")));
assert_eq!(read(node, "from/b").await, Some(json!("b")));
peers_are_node_ids(node).await;
}
}
fn ping(node: &AppState) -> ParsedMessage {
ParsedMessage::Ping(Keepalive {
heads: HeadsSummary::of(Vec::new()),
epoch: node.local_epoch(),
epoch_seq: 0,
ready: false,
syncs_with_you: false,
})
}
fn who(key: &NodeKey, from: &str, to: &str) -> ParsedMessage {
ParsedMessage::Who(IdentityProof {
key: key.public(),
signature: key.sign(&signed(WHO_LABEL, from, to)),
})
}
/// A proof counts only for the address it was made at: messages from an address with
/// a proof made elsewhere are dropped, and the node never hears of them.
#[tokio::test(flavor = "multi_thread", worker_threads = 4)]
async fn a_proof_holds_only_at_its_address() {
let sim = Sim::with_identity(53);
let a = sim.start("a", &[], Start::Genesis);
sim.wait_ready(&[&a], SOON).await;
let ghost = NodeKey::from_seed([9; 32]);
// Made for another sender address, or for another recipient.
for forged in [
who(&ghost, "sim:elsewhere", "sim:a"),
who(&ghost, "sim:ghost", "sim:b"),
] {
sim.net.inject("ghost", "a", &forged).await.unwrap();
sim.net.inject("ghost", "a", &ping(&a)).await.unwrap();
assert!(a.get_peer_state(&ghost.id()).await.is_none());
}
sim.net
.inject("ghost", "a", &who(&ghost, "sim:ghost", "sim:a"))
.await
.unwrap();
sim.net.inject("ghost", "a", &ping(&a)).await.unwrap();
assert!(a.get_peer_state(&ghost.id()).await.is_some());
// Known by its node ID, not by its address.
assert!(a.get_peer_state("ghost").await.is_none());
}
|