#![allow(clippy::items_after_statements)]
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
use std::rc::Rc;
use std::time::{Duration, Instant};
use super::*;
use crate::config::{Config, WallClock};
use crate::constants::{
HANDSHAKE_GIVEUP, INIT_PACKET_LEN, MAC1_LEN, PKT_HANDSHAKE_INIT, PKT_HANDSHAKE_RESP,
RESP_PACKET_LEN, RETRANSMIT_BASE, RETRANSMIT_JITTER_MAX, TS_GUARD_ORPHAN_CAP,
TS_GUARD_ORPHAN_TTL, VERSION,
};
use crate::core::{ConnectionId, Disposition, EndpointOutput, Role, Timestamp};
use crate::error::{AcceptError, AuthError, ConnectError, IntroError};
use crate::identity::{Identity, PublicKeyOf};
use crate::packet::mac::Mac1Key;
use crate::testutil::{CountingIdentity, DhCounter};
type Suite = crate::packet::ReferenceSuite;
type Id = CountingIdentity<Suite>;
type Pk = PublicKeyOf<Id>;
#[derive(Debug, Default)]
struct Drained {
outs: Vec<EndpointOutput<Suite>>,
deadline: Option<Instant>,
}
impl Drained {
fn transmits(&self) -> Vec<(SocketAddr, Vec<u8>)> {
self.outs
.iter()
.filter_map(|o| match o {
EndpointOutput::Transmit(t) => Some((t.to, t.data.clone())),
_ => None,
})
.collect()
}
fn intros(&self) -> Vec<(IntroId, SocketAddr)> {
self.outs
.iter()
.filter_map(|o| match o {
EndpointOutput::IntroReady(id, src) => Some((*id, *src)),
_ => None,
})
.collect()
}
fn installs(&self) -> Vec<ConnectionId> {
self.outs
.iter()
.filter_map(|o| match o {
EndpointOutput::ToConnection(id, _) => Some(*id),
_ => None,
})
.collect()
}
fn install_roles(&self) -> Vec<Role> {
self.outs
.iter()
.filter_map(|o| match o {
EndpointOutput::ToConnection(_, ev) => Some(ev.role),
_ => None,
})
.collect()
}
fn failures(&self) -> Vec<(ConnectionId, ConnectError)> {
self.outs
.iter()
.filter_map(|o| match o {
EndpointOutput::HandshakeFailed(id, e) => Some((*id, e.clone())),
_ => None,
})
.collect()
}
fn one_transmit(&self) -> (SocketAddr, Vec<u8>) {
let v = self.transmits();
assert_eq!(v.len(), 1, "expected exactly one Transmit, got {}", v.len());
v[0].clone()
}
fn one_intro(&self) -> (IntroId, SocketAddr) {
let v = self.intros();
assert_eq!(v.len(), 1, "expected exactly one IntroReady, got {v:?}");
v[0]
}
fn is_silent(&self) -> bool {
self.outs.is_empty()
}
fn timed_out(&self) -> bool {
self.failures()
.iter()
.any(|(_, e)| *e == ConnectError::TimedOut)
}
}
struct FrozenClock(Timestamp);
impl WallClock for FrozenClock {
fn now(&self) -> Timestamp {
self.0
}
}
struct Ep {
ep: Endpoint<Id>,
dhs: DhCounter,
public_static: Pk,
addr: SocketAddr,
wall: Timestamp,
}
impl Ep {
fn new(now: Instant, key_seed: u8, rng_seed: u8, addr: SocketAddr, wall: Timestamp) -> Self {
let identity: Id = CountingIdentity::seeded([key_seed; 32]);
let dhs = identity.counter();
let public_static = *identity.public_static();
let config = Config::default().with_clock(Rc::new(FrozenClock(wall)));
let ep = Endpoint::new(now, config, identity, [rng_seed; 32]);
Ep {
ep,
dhs,
public_static,
addr,
wall,
}
}
fn canonical(&self) -> &[u8] {
self.public_static.as_ref()
}
fn mac1_key(&self) -> Mac1Key {
Mac1Key::derive(self.canonical())
}
fn nth_timestamp(&self, n: usize) -> Timestamp {
assert!(n >= 1, "initiations are 1-based");
let mut t = self.wall;
for _ in 1..n {
t = next_timestamp(t);
}
t
}
fn drain(&mut self) -> Drained {
let mut d = Drained::default();
for _ in 0..100_000 {
match self.ep.poll_output() {
EndpointOutput::Timeout(t) => {
d.deadline = t;
return d;
}
other => d.outs.push(other),
}
}
panic!("poll_output() did not reach the terminal Timeout in 100_000 outputs (§16.4)");
}
fn datagram(&mut self, now: Instant, src: SocketAddr, dgram: &[u8]) -> (Disposition, Drained) {
let disp = self.ep.handle_datagram(now, src, dgram);
(disp, self.drain())
}
fn feed(&mut self, now: Instant, src: SocketAddr, dgram: &[u8]) -> Drained {
self.datagram(now, src, dgram).1
}
fn timeout(&mut self, now: Instant) -> Drained {
self.ep.handle_timeout(now);
self.drain()
}
fn dial(&mut self, now: Instant, remote: SocketAddr, peer: &Pk) -> (ConnectionId, Drained) {
let (id, _conn) = self
.ep
.mint_pending(now, remote, *peer, ())
.expect("mint_pending should succeed for a static with no connection");
self.ep.start_attempt(now, id);
(id, self.drain())
}
fn mint_only(&mut self, now: Instant, remote: SocketAddr, peer: &Pk) -> ConnectionId {
let (id, _conn) = self
.ep
.mint_pending(now, remote, *peer, ())
.expect("mint_pending should succeed for a static with no connection");
id
}
fn dh(&self) -> u32 {
self.dhs.get()
}
fn reset_dh(&self) {
self.dhs.reset();
}
fn present(&self, id: IntroId) -> bool {
self.ep.intro_source(id).is_some()
}
fn hints(&self) -> Vec<SocketAddr> {
self.ep.hints()
}
fn basis(&self, peer: &[u8]) -> Option<Option<Timestamp>> {
self.ep.replacement_basis(peer)
}
fn greatest(&self, peer: &[u8]) -> Option<Timestamp> {
self.ep.greatest(peer)
}
}
const T_BASE_SECS: u64 = 1_700_000_000;
fn t0() -> Instant {
Instant::now()
}
fn v4(a: u8, port: u16) -> SocketAddr {
SocketAddr::new(IpAddr::V4(Ipv4Addr::new(10, 0, 0, a)), port)
}
fn next_timestamp(t: Timestamp) -> Timestamp {
if t.nanos() >= 999_999_999 {
Timestamp::new(t.secs() + 1, 0)
} else {
Timestamp::new(t.secs(), t.nanos() + 1)
}
}
fn init_sender_index(dgram: &[u8]) -> u32 {
u32::from_le_bytes(dgram[2..6].try_into().expect("init header"))
}
fn resp_indices(dgram: &[u8]) -> (u32, u32) {
(
u32::from_le_bytes(dgram[2..6].try_into().expect("resp header")),
u32::from_le_bytes(dgram[6..10].try_into().expect("resp header")),
)
}
fn forged_init(recipient: &Ep, sender_index: u32, filler: u8) -> Vec<u8> {
let mut d = vec![filler; INIT_PACKET_LEN];
d[0] = PKT_HANDSHAKE_INIT;
d[1] = VERSION;
d[2..6].copy_from_slice(&sender_index.to_le_bytes());
let (preimage, tag) = d.split_at_mut(INIT_PACKET_LEN - MAC1_LEN);
let t = recipient.mac1_key().tag(preimage);
tag.copy_from_slice(&t);
d
}
fn forge_tail(genuine_msg1: &[u8], recipient: &Ep) -> Vec<u8> {
let mut d = genuine_msg1.to_vec();
let last_msg1_byte = INIT_PACKET_LEN - MAC1_LEN - 1;
d[last_msg1_byte] ^= 0xFF;
let (preimage, tag) = d.split_at_mut(INIT_PACKET_LEN - MAC1_LEN);
let t = recipient.mac1_key().tag(preimage);
tag.copy_from_slice(&t);
d
}
fn real_msg1(initiator: &mut Ep, now: Instant, responder: &Ep) -> Vec<u8> {
let peer = responder.public_static;
let (_id, drained) = initiator.dial(now, responder.addr, &peer);
let (to, data) = drained.one_transmit();
assert_eq!(
to, responder.addr,
"§5.5 step 1 sends to the dialled address"
);
assert_eq!(data.len(), INIT_PACKET_LEN, "§3.2, exact");
data
}
const SEED_X: u8 = 7;
const SEED_Y: u8 = 9;
fn static_bytes(seed: u8) -> Vec<u8> {
let id: Id = CountingIdentity::seeded([seed; 32]);
id.public_static().as_ref().to_vec()
}
fn seeds_by_key_order() -> (u8, u8) {
let x = static_bytes(SEED_X);
let y = static_bytes(SEED_Y);
assert_ne!(x, y, "two distinct seeds must give two distinct statics");
if x < y {
(SEED_X, SEED_Y)
} else {
(SEED_Y, SEED_X)
}
}
const WALL_WINNER: Timestamp = Timestamp::new(T_BASE_SECS, 0);
const WALL_LOSER: Timestamp = Timestamp::new(T_BASE_SECS, 500);
fn tie_pair(now: Instant) -> (Ep, Ep) {
let (small, large) = seeds_by_key_order();
let winner = Ep::new(now, small, 0x11, v4(1, 1), WALL_WINNER);
let loser = Ep::new(now, large, 0x22, v4(2, 2), WALL_LOSER);
assert!(
winner.canonical() < loser.canonical(),
"the fixture must hand back the smaller static first (§6.7)"
);
(winner, loser)
}
fn third_party(now: Instant) -> Ep {
Ep::new(
now,
0x5B,
0x33,
v4(3, 3),
Timestamp::new(T_BASE_SECS, 900_000),
)
}
fn past_retransmit() -> Duration {
RETRANSMIT_BASE + RETRANSMIT_JITTER_MAX + Duration::from_millis(1)
}
fn past_giveup() -> Duration {
HANDSHAKE_GIVEUP + Duration::from_secs(1)
}
#[test]
fn the_two_seeded_statics_differ_and_the_fixture_orders_them() {
let (winner, loser) = tie_pair(t0());
assert_ne!(
winner.canonical(),
loser.canonical(),
"§6.7: equal statics cannot occur"
);
assert!(
winner.canonical() < loser.canonical(),
"§6.7: the lexicographically smaller static is the winning initiator, \
and tie_pair must return it first"
);
assert_ne!(winner.nth_timestamp(1), loser.nth_timestamp(1));
let other = third_party(t0());
assert_ne!(other.canonical(), winner.canonical());
assert_ne!(other.canonical(), loser.canonical());
}
#[test]
fn the_fixture_predicts_the_initiation_timestamps_it_asserts_on() {
let now = t0();
let (mut a, b) = tie_pair(now);
let first = real_msg1(&mut a, now, &b);
assert_eq!(first.len(), INIT_PACKET_LEN);
let d = a.timeout(now + past_retransmit());
let (_, second) = d.one_transmit();
assert_ne!(first, second, "§5.5 rule 2: every retransmit is fresh");
assert_eq!(a.nth_timestamp(1), a.wall);
assert_eq!(a.nth_timestamp(2), next_timestamp(a.wall));
assert!(
a.nth_timestamp(2) > a.nth_timestamp(1),
"§17.2's monotone forcing"
);
}
#[test]
fn an_init_from_a_non_hint_source_parks_at_zero_dh() {
let now = t0();
let (mut local, mut peer) = tie_pair(now);
let msg1 = real_msg1(&mut peer, now, &local);
assert!(
local.hints().is_empty(),
"the local endpoint has dialled nobody, so §6.5's hint set is empty"
);
local.reset_dh();
let d = local.feed(now, peer.addr, &msg1);
assert_eq!(local.dh(), 0, "§6.1: parking is 0 DH, §6.5 step 2");
let (_id, src) = d.one_intro();
assert_eq!(src, peer.addr);
assert!(d.transmits().is_empty(), "parking writes nothing");
}
#[test]
fn an_init_from_a_hint_source_spends_one_dh_on_the_eager_read() {
let now = t0();
let (mut local, peer) = tie_pair(now);
let mut other = third_party(now);
let msg1 = real_msg1(&mut other, now, &local);
local.dial(now, peer.addr, &peer.public_static);
assert!(
local.hints().contains(&peer.addr),
"§17.4: an in-flight outbound pending's dialled address is a hint"
);
local.reset_dh();
let d = local.feed(now, peer.addr, &msg1);
assert_eq!(
local.dh(),
1,
"§6.5 step 3: the eager split intro read is 1 DH (`es`)"
);
let (_id, src) = d.one_intro();
assert_eq!(
src, peer.addr,
"§6.5 step 3: a peer sharing a source with a dialled address still \
surfaces as an Intro"
);
assert!(
d.transmits().is_empty(),
"a demotion writes nothing on the wire"
);
}
#[test]
fn a_demoted_intro_returns_its_cached_claim_at_zero_incremental_dh() {
let now = t0();
let (mut local, peer) = tie_pair(now);
let mut other = third_party(now);
let msg1 = real_msg1(&mut other, now, &local);
local.dial(now, peer.addr, &peer.public_static);
let d = local.feed(now, peer.addr, &msg1);
let (id, _) = d.one_intro();
local.reset_dh();
let claimed = local
.ep
.read_identity(now, id)
.expect("the demoted chain's claim is already read");
assert_eq!(
local.dh(),
0,
"§6.5 step 3: read_identity() on a demoted intro is 0 incremental DH"
);
assert_eq!(
claimed.as_ref(),
other.canonical(),
"the cached claim is the third party's static, not the dialled peer's"
);
}
#[test]
fn a_demoted_intro_keeps_section_6_1s_cumulative_ladder() {
let now = t0();
let (mut local, peer) = tie_pair(now);
let mut other = third_party(now);
let msg1 = real_msg1(&mut other, now, &local);
local.dial(now, peer.addr, &peer.public_static);
local.reset_dh();
let d = local.feed(now, peer.addr, &msg1);
let (id, _) = d.one_intro();
assert_eq!(local.dh(), 1, "arrival + eager read: 1 DH cumulative");
local.ep.read_identity(now, id).expect("claim already read");
assert_eq!(local.dh(), 1, "§6.1: read_identity is 1 DH cumulative");
local
.ep
.authenticate(now, id, &())
.expect("a genuine msg1 authenticates");
assert_eq!(local.dh(), 2, "§6.1: authenticate is 2 DH cumulative");
let (_conn, _c) = local.ep.accept(now, id).expect("NONE static, fresh accept");
let _ = local.drain();
assert_eq!(local.dh(), 4, "§6.1: accept is 4 DH cumulative");
}
#[test]
fn an_established_connections_address_is_not_a_hint() {
let now = t0();
let (mut local, mut peer) = tie_pair(now);
let msg1 = real_msg1(&mut peer, now, &local);
let d = local.feed(now, peer.addr, &msg1);
let (id, _) = d.one_intro();
local.ep.authenticate(now, id, &()).expect("genuine msg1");
local.ep.accept(now, id).expect("NONE static, fresh accept");
let _ = local.drain();
assert!(
local.basis(peer.canonical()).is_some(),
"the accept installed a connection for that static"
);
assert!(
!local.hints().contains(&peer.addr),
"§17.4: established connections contribute no hints"
);
let msg1b = next_retransmit_init(&mut peer, now + past_retransmit());
local.reset_dh();
let d = local.feed(now + past_retransmit(), peer.addr, &msg1b);
assert_eq!(
local.dh(),
0,
"§6.5 step 2: not a hint, so no eager read — 0 DH"
);
assert_eq!(
d.intros().len(),
1,
"it parks and surfaces as an ordinary Intro"
);
}
fn next_retransmit_init(peer: &mut Ep, now: Instant) -> Vec<u8> {
let d = peer.timeout(now);
let (_, data) = d.one_transmit();
assert_eq!(data.len(), INIT_PACKET_LEN);
data
}
#[test]
fn a_source_port_rewrite_misses_the_hint_set_and_parks() {
let now = t0();
let (mut local, mut peer) = tie_pair(now);
let msg1 = real_msg1(&mut peer, now, &local);
local.dial(now, peer.addr, &peer.public_static);
let rewritten = SocketAddr::new(peer.addr.ip(), peer.addr.port() ^ 0x0F00);
assert_ne!(rewritten, peer.addr);
assert!(!local.hints().contains(&rewritten));
local.reset_dh();
let d = local.feed(now, rewritten, &msg1);
assert_eq!(local.dh(), 0, "§6.5 step 2: not a hint, so no eager read");
let (_id, src) = d.one_intro();
assert_eq!(src, rewritten, "it parks as an ordinary Intro");
assert!(
d.transmits().is_empty(),
"no tie-break ran, so no msg2 was written"
);
assert_eq!(
local.greatest(peer.canonical()),
None,
"§6.6 never ran, so nothing was recorded"
);
assert_eq!(
local.basis(peer.canonical()),
Some(None),
"our own pending is untouched: still ours, still dialled"
);
}
#[test]
fn read_identity_intercepts_a_parked_intro_whose_claim_is_a_pending_remote() {
for local_is_winner in [true, false] {
let now = t0();
let (winner, loser) = tie_pair(now);
let (mut local, mut peer) = if local_is_winner {
(winner, loser)
} else {
(loser, winner)
};
let msg1 = real_msg1(&mut peer, now, &local);
let d = local.feed(now, peer.addr, &msg1);
let (id, _) = d.one_intro();
local.dial(now, peer.addr, &peer.public_static);
let err = local
.ep
.read_identity(now, id)
.expect_err("§6.5 step 4: the interception denies the application an identity");
let d = local.drain();
assert_eq!(
err,
IntroError::Internal,
"§6.5 step 4 names the variant, and §18.1 defines it as \
'the initiation belonged to a pending outbound dial and was consumed' \
(local_is_winner = {local_is_winner})"
);
assert_eq!(
local.greatest(peer.canonical()),
Some(peer.nth_timestamp(1)),
"§6.6: the tie-break really ran (local_is_winner = {local_is_winner})"
);
if local_is_winner {
assert!(d.is_silent(), "§6.6 step 3: the winner drops it silently");
} else {
assert_eq!(d.transmits().len(), 1, "§6.6 step 4: the loser writes msg2");
assert_eq!(d.installs().len(), 1, "and completes its own Connecting");
}
}
}
#[test]
fn a_second_read_identity_after_the_static_became_pending_does_not_intercept() {
let now = t0();
let (mut local, mut peer) = tie_pair(now);
let msg1 = real_msg1(&mut peer, now, &local);
let d = local.feed(now, peer.addr, &msg1);
let (id, _) = d.one_intro();
let first = local
.ep
.read_identity(now, id)
.expect("an ordinary parked intro reveals its claim");
assert_eq!(first.as_ref(), peer.canonical());
local.dial(now, peer.addr, &peer.public_static);
local.reset_dh();
let second = local
.ep
.read_identity(now, id)
.expect("ruling 74: idempotent, and §6.4:1439 says the interception cannot fire here");
let d = local.drain();
assert_eq!(second.as_ref(), peer.canonical(), "the same claim, again");
assert_eq!(local.dh(), 0, "ruling 74: 0 DH, opening no provider");
assert!(d.is_silent(), "no tie-break ran: nothing was written");
assert_eq!(
local.greatest(peer.canonical()),
None,
"no tie-break ran, so nothing was recorded"
);
assert!(local.present(id), "the chain is still the application's");
}
#[test]
fn a_second_authenticate_is_idempotent_at_zero_incremental_dh() {
let now = t0();
let (mut local, mut peer) = tie_pair(now);
let msg1 = real_msg1(&mut peer, now, &local);
let d = local.feed(now, peer.addr, &msg1);
let (id, _) = d.one_intro();
local.ep.read_identity(now, id).expect("readable");
let _ = local.drain();
let (first_peer, first_ts) = local
.ep
.authenticate(now, id, &())
.expect("a genuine msg1 authenticates");
let _ = local.drain();
assert_eq!(local.dh(), 2, "§6.1: authenticate is 2 DH cumulative");
assert_eq!(first_peer.as_ref(), peer.canonical(), "the proven static");
assert_eq!(
first_ts,
peer.nth_timestamp(1),
"the initiation's own timestamp, not some default"
);
assert!(local.present(id), "the chain is still staged");
local.reset_dh();
let (second_peer, second_ts) = local
.ep
.authenticate(now, id, &())
.expect("ruling 267: authenticate() is idempotent at Proven");
let d = local.drain();
assert_eq!(
second_peer.as_ref(),
first_peer.as_ref(),
"ruling 267: the same peer, again"
);
assert_eq!(second_ts, first_ts, "ruling 267: the same timestamp, again");
assert_eq!(local.dh(), 0, "ruling 267: zero incremental DH");
assert!(d.is_silent(), "an idempotent read writes nothing");
assert!(
local.present(id),
"and the chain is still the application's"
);
}
#[test]
fn an_internally_routed_init_never_surfaces_as_an_intro() {
for local_is_winner in [true, false] {
let now = t0();
let (winner, loser) = tie_pair(now);
let (mut local, mut peer) = if local_is_winner {
(winner, loser)
} else {
(loser, winner)
};
let msg1 = real_msg1(&mut peer, now, &local);
local.dial(now, peer.addr, &peer.public_static);
let (disp, d) = local.datagram(now, peer.addr, &msg1);
assert!(
d.intros().is_empty(),
"§6.5 step 3: the application never sees it (local_is_winner = {local_is_winner})"
);
assert_eq!(
disp,
Disposition::Done,
"the endpoint consumed it; nothing routes to a connection core"
);
}
}
fn crossing(now: Instant, local: &mut Ep, peer: &mut Ep) -> (ConnectionId, Vec<u8>) {
let msg1 = real_msg1(peer, now, local);
let (conn, d) = local.dial(now, peer.addr, &peer.public_static);
assert_eq!(d.transmits().len(), 1, "our own msg1 went out");
assert!(
local.hints().contains(&peer.addr),
"§17.4: it is now a hint"
);
(conn, msg1)
}
fn sides(now: Instant, local_is_winner: bool) -> (Ep, Ep) {
let (winner, loser) = tie_pair(now);
if local_is_winner {
(winner, loser)
} else {
(loser, winner)
}
}
#[test]
fn winning_the_internal_tie_break_costs_two_dh() {
let now = t0();
let (mut local, mut peer) = sides(now, true);
let (_conn, msg1) = crossing(now, &mut local, &mut peer);
local.reset_dh();
let _ = local.feed(now, peer.addr, &msg1);
assert_eq!(
local.dh(),
2,
"§6.5 step 3's `es` plus §6.6 step 1's `ss`, and nothing else"
);
}
#[test]
fn losing_the_internal_tie_break_costs_four_dh() {
let now = t0();
let (mut local, mut peer) = sides(now, false);
let (_conn, msg1) = crossing(now, &mut local, &mut peer);
local.reset_dh();
let _ = local.feed(now, peer.addr, &msg1);
assert_eq!(
local.dh(),
4,
"§6.5 step 3's `es`, §6.6 step 1's `ss`, and step 4's `ee` + `se`"
);
}
#[test]
fn winning_the_internal_tie_break_drops_the_inbound_silently() {
let now = t0();
let (mut local, mut peer) = sides(now, true);
let (_conn, msg1) = crossing(now, &mut local, &mut peer);
let d = local.feed(now, peer.addr, &msg1);
assert!(
d.is_silent(),
"§6.6 step 3: a winner-side drop emits nothing at all, got {:?}",
d.outs
);
}
#[test]
fn winning_the_internal_tie_break_leaves_the_pending_retransmitting() {
let now = t0();
let (mut local, mut peer) = sides(now, true);
let (_conn, msg1) = crossing(now, &mut local, &mut peer);
let _ = local.feed(now, peer.addr, &msg1);
let later = now + past_retransmit();
let d = local.timeout(later);
assert!(
d.deadline.is_some(),
"§16.5: a live pending arms a retransmit and a give-up"
);
let (to, data) = d.one_transmit();
assert_eq!(
to, peer.addr,
"§5.5: the retransmit goes to the dialled address"
);
assert_eq!(data.len(), INIT_PACKET_LEN);
assert_eq!(data[0], PKT_HANDSHAKE_INIT, "it is a fresh initiation");
assert!(
d.failures().is_empty(),
"no give-up: the pending is alive and well"
);
assert_eq!(
local.basis(peer.canonical()),
Some(None),
"§17.4: still ours, still dialled"
);
assert!(
local.hints().contains(&peer.addr),
"an in-flight outbound pending is still a hint"
);
}
#[test]
fn winning_the_internal_tie_break_records_the_losers_timestamp() {
let now = t0();
let (mut local, mut peer) = sides(now, true);
let (_conn, msg1) = crossing(now, &mut local, &mut peer);
assert_eq!(
local.greatest(peer.canonical()),
None,
"nothing recorded before the tie-break"
);
let _ = local.feed(now, peer.addr, &msg1);
assert_eq!(
local.greatest(peer.canonical()),
Some(peer.nth_timestamp(1)),
"§6.6 step 3 / §6.7: the winner records the loser's timestamp"
);
}
#[test]
fn the_replacement_basis_is_complementary_across_the_two_key_orders() {
let now = t0();
let (mut w_local, mut w_peer) = sides(now, true);
let (_c, w_msg1) = crossing(now, &mut w_local, &mut w_peer);
let _ = w_local.feed(now, w_peer.addr, &w_msg1);
let winner_basis = w_local.basis(w_peer.canonical());
let (mut l_local, mut l_peer) = sides(now, false);
let (_c, l_msg1) = crossing(now, &mut l_local, &mut l_peer);
let _ = l_local.feed(now, l_peer.addr, &l_msg1);
let loser_basis = l_local.basis(l_peer.canonical());
assert_eq!(
winner_basis,
Some(None),
"§17.4: `None` when we dialled, and a tie-break we won is one of those"
);
assert_eq!(
loser_basis,
Some(Some(l_peer.nth_timestamp(1))),
"§17.4: the tie-break loser's admit step (§6.6 step 4) writes `Some(t)`"
);
assert_ne!(
winner_basis, loser_basis,
"the two key orders must reach different states, or the comparison \
is not being applied at all"
);
}
#[test]
fn losing_the_internal_tie_break_writes_msg2_answering_the_inbound_index() {
let now = t0();
let (mut local, mut peer) = sides(now, false);
let (_conn, msg1) = crossing(now, &mut local, &mut peer);
let d = local.feed(now, peer.addr, &msg1);
let (to, data) = d.one_transmit();
assert_eq!(to, peer.addr, "§5.6: anchored at the msg1 source");
assert_eq!(data.len(), RESP_PACKET_LEN, "§3.3, exact");
assert_eq!(data[0], PKT_HANDSHAKE_RESP);
let (_ours, theirs) = resp_indices(&data);
assert_eq!(
theirs,
init_sender_index(&msg1),
"§3.3: the receiver_index answers the initiation we read"
);
}
#[test]
fn the_losers_msg2_anchors_at_the_msg1_source_not_the_dialled_address() {
let now = t0();
let (mut local, mut peer) = sides(now, false);
let msg1 = real_msg1(&mut peer, now, &local);
local.dial(now, peer.addr, &peer.public_static);
let rewritten = SocketAddr::new(peer.addr.ip(), peer.addr.port() ^ 0x0F00);
let d = local.feed(now, rewritten, &msg1);
let (id, _) = d.one_intro();
let err = local
.ep
.read_identity(now, id)
.expect_err("§6.5 step 4 intercepts");
assert_eq!(err, IntroError::Internal);
let d = local.drain();
let (to, data) = d.one_transmit();
assert_eq!(
to, rewritten,
"§5.6: the responder anchors at the initiation's msg1 source"
);
assert_ne!(to, peer.addr, "and that is not the address we dialled");
assert_eq!(data.len(), RESP_PACKET_LEN);
}
#[test]
fn losing_the_internal_tie_break_completes_the_pendings_own_connection() {
let now = t0();
let (mut local, mut peer) = sides(now, false);
let (conn, msg1) = crossing(now, &mut local, &mut peer);
let d = local.feed(now, peer.addr, &msg1);
let installs = d.installs();
assert_eq!(installs.len(), 1, "exactly one Install, got {installs:?}");
assert_eq!(
installs[0], conn,
"§6.7: the tie-break's Install resolves the pending's own Connecting"
);
assert!(
d.failures().is_empty(),
"§6.7: the loser cancels its pending with no give-up and no error"
);
}
#[test]
fn losing_the_internal_tie_break_cancels_the_pending_so_it_neither_retransmits_nor_gives_up() {
let now = t0();
let (mut local, mut peer) = sides(now, false);
let (_conn, msg1) = crossing(now, &mut local, &mut peer);
let _ = local.feed(now, peer.addr, &msg1);
let d = local.timeout(now + past_retransmit());
assert!(
d.transmits().is_empty(),
"the pending is gone: nothing to retransmit, got {:?}",
d.transmits()
);
let d = local.timeout(now + past_giveup());
assert!(
!d.timed_out(),
"the pending is gone: nothing to give up on, got {:?}",
d.failures()
);
}
#[test]
fn losing_the_internal_tie_break_drops_the_dialled_address_from_the_hint_set() {
let now = t0();
let (mut local, mut peer) = sides(now, false);
let (_conn, msg1) = crossing(now, &mut local, &mut peer);
assert!(local.hints().contains(&peer.addr), "a hint while dialling");
let _ = local.feed(now, peer.addr, &msg1);
assert!(
!local.hints().contains(&peer.addr),
"§17.4: established connections contribute no hints, got {:?}",
local.hints()
);
}
#[test]
fn losing_the_internal_tie_break_records_the_admitted_timestamp() {
let now = t0();
let (mut local, mut peer) = sides(now, false);
let (_conn, msg1) = crossing(now, &mut local, &mut peer);
let _ = local.feed(now, peer.addr, &msg1);
assert_eq!(
local.greatest(peer.canonical()),
Some(peer.nth_timestamp(1)),
"§6.6 step 4 records the admitted timestamp"
);
}
#[test]
fn losing_the_internal_tie_break_pins_the_record_against_orphan_aging() {
let now = t0();
let (mut local, mut peer) = sides(now, false);
let (_conn, msg1) = crossing(now, &mut local, &mut peer);
let _ = local.feed(now, peer.addr, &msg1);
assert!(
local.ep.guard_pins(peer.canonical()) >= 1,
"the installed connection pins its static's guard entry (§17.1)"
);
let _ = local.timeout(now + TS_GUARD_ORPHAN_TTL + Duration::from_millis(1));
assert_eq!(
local.greatest(peer.canonical()),
Some(peer.nth_timestamp(1)),
"§17.1: a pinned entry is never evicted or aged"
);
}
#[test]
fn the_post_mortem_pin_survives_orphan_aging_and_a_full_lru_flush() {
let now = t0();
let (mut local, mut peer) = sides(now, false);
let (conn, msg1) = crossing(now, &mut local, &mut peer);
let d = local.feed(now, peer.addr, &msg1);
assert_eq!(d.installs(), vec![conn], "the tie-break installed");
let (ours, _theirs) = resp_indices(&d.one_transmit().1);
assert_eq!(
local.greatest(peer.canonical()),
Some(peer.nth_timestamp(1)),
"§6.6 step 4 recorded the admitted timestamp"
);
assert_eq!(
local.ep.guard_pins(peer.canonical()),
1,
"§17.1: the live connection pins its static's entry"
);
local
.ep
.handle_connection_event(now, conn, ToEndpoint::Retired { our_index: ours });
let d = local.drain();
assert_eq!(
local.ep.guard_pins(peer.canonical()),
0,
"the entry is unpinned — only `exempt_until` can protect it from here"
);
assert_eq!(
local.greatest(peer.canonical()),
Some(peer.nth_timestamp(1)),
"the record outlived the connection"
);
assert_eq!(
d.deadline,
Some(now + HANDSHAKE_GIVEUP),
"§17.1: the exemption is stamped at death + HANDSHAKE_GIVEUP, and it \
dominates the ordinary orphan window — a bare TS_GUARD_ORPHAN_TTL \
deadline here would mean no exemption was written at all"
);
let aged = now + TS_GUARD_ORPHAN_TTL + Duration::from_nanos(1);
let d = local.timeout(aged);
assert_eq!(
local.greatest(peer.canonical()),
Some(peer.nth_timestamp(1)),
"§17.1: the exemption survives orphan aging"
);
assert_eq!(
d.deadline,
Some(now + HANDSHAKE_GIVEUP),
"and the announced deadline is still the exemption's"
);
let ts = peer.nth_timestamp(1);
let fill_from = aged + Duration::from_millis(1);
for i in 0..TS_GUARD_ORPHAN_CAP {
local.ep.guard.record(
&filler_static(i),
ts,
fill_from + Duration::from_millis(i as u64),
);
}
assert!(
local.ep.guard.greatest(&filler_static(0)).is_some(),
"the LRU evicted below TS_GUARD_ORPHAN_CAP"
);
local.ep.guard.record(
&filler_static(TS_GUARD_ORPHAN_CAP),
ts,
fill_from + Duration::from_millis(TS_GUARD_ORPHAN_CAP as u64),
);
assert!(
local.ep.guard.greatest(&filler_static(0)).is_none(),
"the flush did not happen — nothing below is a test of surviving it"
);
assert!(
local.ep.guard.greatest(&filler_static(1)).is_some(),
"exactly one victim: the cap evicts down to TS_GUARD_ORPHAN_CAP, not further"
);
assert_eq!(
local.greatest(peer.canonical()),
Some(peer.nth_timestamp(1)),
"§17.1: the exempt entry survived a full LRU flush, as the oldest \
entry in the tier"
);
let inside = now + HANDSHAKE_GIVEUP - Duration::from_secs(1);
let d = local.feed(inside, v4(9, 1), &msg1);
let (replay, _) = d.one_intro();
assert_eq!(
local.ep.authenticate(inside, replay, &()),
Err(AuthError::Replay),
"§6.7: the captured initiation is single-use while its entry survives"
);
let _ = local.drain();
let after = now + HANDSHAKE_GIVEUP + Duration::from_nanos(1);
let _ = local.timeout(after);
assert_eq!(
local.greatest(peer.canonical()),
None,
"§17.1: the extension lapsed and the ordinary orphan — already \
TS_GUARD_ORPHAN_TTL past its stamp — aged out"
);
let d = local.feed(after, v4(9, 2), &msg1);
let (again, _) = d.one_intro();
assert!(
local.ep.authenticate(after, again, &()).is_ok(),
"§6.7's single-use bound is conditional: past the horizon the same \
captured initiation is re-admitted"
);
}
fn filler_static(i: usize) -> Vec<u8> {
let mut key = vec![0xF0; 33];
key[1] = (i & 0xFF) as u8;
key[2] = ((i >> 8) & 0xFF) as u8;
key
}
#[test]
fn the_internal_tie_break_takes_opposite_branches_in_the_two_key_orders() {
let now = t0();
let (mut w_local, mut w_peer) = sides(now, true);
let (_c, w_msg1) = crossing(now, &mut w_local, &mut w_peer);
let w = w_local.feed(now, w_peer.addr, &w_msg1);
let (mut l_local, mut l_peer) = sides(now, false);
let (_c, l_msg1) = crossing(now, &mut l_local, &mut l_peer);
let l = l_local.feed(now, l_peer.addr, &l_msg1);
assert!(w.is_silent(), "smaller static ⇒ winner ⇒ silent drop");
assert_eq!(l.transmits().len(), 1, "larger static ⇒ loser ⇒ msg2");
assert_eq!(l.installs().len(), 1, "larger static ⇒ loser ⇒ Install");
assert!(w.installs().is_empty(), "the winner installs nothing here");
}
#[test]
fn the_tie_break_loser_installs_as_responder_and_a_msg2_completion_as_initiator() {
let now = t0();
let (mut l_local, mut l_peer) = sides(now, false);
let (_c, l_msg1) = crossing(now, &mut l_local, &mut l_peer);
let l = l_local.feed(now, l_peer.addr, &l_msg1);
assert_eq!(
l.install_roles(),
vec![Role::Responder],
"§6.6 step 4: a dialling peer that loses the tie-break installs as responder"
);
let (mut a, mut b) = sides(now, true);
let msg1 = real_msg1(&mut a, now, &b);
let (id, _) = b.feed(now, a.addr, &msg1).one_intro();
b.ep.authenticate(now, id, &()).expect("genuine msg1");
b.ep.accept(now, id).expect("NONE static, fresh accept");
let msg2 = b.drain().one_transmit().1;
let d = a.feed(now, b.addr, &msg2);
assert_eq!(
d.install_roles(),
vec![Role::Initiator],
"a dial completed by msg2 installs as initiator"
);
}
#[test]
fn a_forged_tail_dies_at_step_one_and_cannot_cancel_a_pending() {
for local_is_winner in [true, false] {
let now = t0();
let (mut local, mut peer) = sides(now, local_is_winner);
let (_conn, genuine) = crossing(now, &mut local, &mut peer);
let forged = forge_tail(&genuine, &local);
assert_ne!(forged, genuine);
local.reset_dh();
let d = local.feed(now, peer.addr, &forged);
assert!(
d.is_silent(),
"§6.6: a step-1 failure is a silent drop (local_is_winner = \
{local_is_winner}), got {:?}",
d.outs
);
assert_eq!(
local.dh(),
2,
"§6.5 step 3's `es` plus §6.6 step 1's `ss`; the tag fails after both"
);
assert_eq!(
local.greatest(peer.canonical()),
None,
"§6.6: nothing recorded on a step-1 failure"
);
assert_eq!(
local.basis(peer.canonical()),
Some(None),
"the pending is untouched"
);
let d = local.timeout(now + past_retransmit());
assert_eq!(
d.transmits().len(),
1,
"the pending is untouched, so it retransmits (local_is_winner = \
{local_is_winner})"
);
}
}
#[test]
fn the_guard_step_refuses_an_older_initiation_without_recording_it() {
let now = t0();
let (mut local, mut peer) = sides(now, true);
let first = real_msg1(&mut peer, now, &local);
let second = {
let d = peer.timeout(now + past_retransmit());
let (_, data) = d.one_transmit();
data
};
assert_ne!(first, second);
local.dial(now, peer.addr, &peer.public_static);
let d = local.feed(now, peer.addr, &second);
assert!(d.is_silent());
assert_eq!(
local.greatest(peer.canonical()),
Some(peer.nth_timestamp(2)),
"the winner recorded the newer initiation"
);
local.reset_dh();
let d = local.feed(now, peer.addr, &first);
assert!(d.is_silent(), "a step-2 failure is a silent drop");
assert_eq!(local.dh(), 2, "step 1 still ran: `es` + `ss`");
assert_eq!(
local.greatest(peer.canonical()),
Some(peer.nth_timestamp(2)),
"§6.6: a step-2 failure records nothing — `greatest` must not walk back"
);
assert_eq!(
local.basis(peer.canonical()),
Some(None),
"the pending is untouched"
);
}
#[test]
fn a_malformed_init_from_a_hint_source_writes_nothing_and_leaves_the_pending_alone() {
let now = t0();
let (mut local, peer) = sides(now, false);
local.dial(now, peer.addr, &peer.public_static);
let junk = forged_init(&local, 0x1234_5678, 0xAB);
let d = local.feed(now, peer.addr, &junk);
assert!(
d.transmits().is_empty(),
"unreadable bytes must not produce a msg2"
);
assert!(d.installs().is_empty(), "nor an Install");
assert!(d.failures().is_empty(), "nor a failure on our own dial");
assert_eq!(
local.greatest(peer.canonical()),
None,
"nothing authenticated, so nothing recorded"
);
assert_eq!(
local.basis(peer.canonical()),
Some(None),
"our pending is untouched"
);
let d = local.timeout(now + past_retransmit());
assert_eq!(d.transmits().len(), 1, "the dial is still running");
}
#[test]
fn both_routes_to_the_comparison_reach_the_same_conclusion() {
for local_is_winner in [true, false] {
let now = t0();
let (mut local, mut peer) = sides(now, local_is_winner);
let msg1 = real_msg1(&mut peer, now, &local);
let d = local.feed(now, peer.addr, &msg1);
let (id, _) = d.one_intro();
local.dial(now, peer.addr, &peer.public_static);
let authed = local.ep.authenticate(now, id, &());
if let Err(e) = &authed {
assert_ne!(
*e,
AuthError::HandshakeFailed,
"§18.1 makes this a security signal and ruling 78 forbids \
pointing it at a peer whose msg1 is genuine"
);
assert_ne!(*e, AuthError::Replay, "the guard admitted this timestamp");
}
if authed.is_ok() {
let _ = local.ep.accept(now, id);
}
let _ = local.drain();
if local_is_winner {
assert_eq!(
local.basis(peer.canonical()),
Some(None),
"winner, by either route: the pending stands and we stay the \
initiator"
);
assert_eq!(
local.greatest(peer.canonical()),
Some(peer.nth_timestamp(1)),
"winner, by either route: the candidate's timestamp is recorded \
(§6.4:1401-1406 — the one `Stale` that keeps its record — and \
§6.7's winner-side record are the same write)"
);
assert!(
local.hints().contains(&peer.addr),
"winner, by either route: the pending is still in flight"
);
} else {
assert_eq!(
local.basis(peer.canonical()),
Some(Some(peer.nth_timestamp(1))),
"loser, by either route: we installed as responder at that \
initiation's timestamp (§17.4)"
);
assert!(
!local.hints().contains(&peer.addr),
"loser, by either route: the pending is cancelled"
);
let d = local.timeout(now + past_giveup());
assert!(
!d.timed_out(),
"loser, by either route: no pending is left to give up"
);
}
}
}
fn ordinary_ordering(
now: Instant,
local: &mut Ep,
peer: &mut Ep,
) -> (IntroId, ConnectionId, Vec<u8>) {
let msg1 = real_msg1(peer, now, local);
let d = local.feed(now, peer.addr, &msg1);
let (intro, _) = d.one_intro();
let claimed = local.ep.read_identity(now, intro).expect("§6.1 stage 1");
assert_eq!(claimed.as_ref(), peer.canonical());
let (conn, d) = local.dial(now, peer.addr, &peer.public_static);
let (_, ours) = d.one_transmit();
local
.ep
.authenticate(now, intro, &())
.expect("a genuine crossing msg1 authenticates");
(intro, conn, ours)
}
#[test]
fn the_pending_branch_winner_returns_stale_and_is_the_one_stale_that_keeps_its_record() {
let now = t0();
let (mut local, mut peer) = sides(now, true);
let (intro, pending_conn, _ours) = ordinary_ordering(now, &mut local, &mut peer);
let refused = local.ep.accept(now, intro);
let d = local.drain();
assert_eq!(
refused.err(),
Some(AcceptError::Stale),
"§6.4: the tie-break winner refuses the accept"
);
assert_eq!(
local.greatest(peer.canonical()),
Some(peer.nth_timestamp(1)),
"§6.4:1401-1406: this `Stale` keeps its record"
);
assert!(d.transmits().is_empty(), "a refused accept writes no msg2");
assert!(d.installs().is_empty(), "and installs no second connection");
assert_eq!(
local.basis(peer.canonical()),
Some(None),
"§6.4: the pending is left in place"
);
let d = local.timeout(now + past_retransmit());
let (to, _) = d.one_transmit();
assert_eq!(to, peer.addr);
assert!(
resolutions(&d, pending_conn).is_empty(),
"§6.4: a refused accept resolves nothing — the dial is still running"
);
let now2 = t0();
let (mut plain, mut stranger) = tie_pair(now2);
let msg1 = real_msg1(&mut stranger, now2, &plain);
let d = plain.feed(now2, stranger.addr, &msg1);
let (id, _) = d.one_intro();
plain
.ep
.authenticate(now2, id, &())
.expect("genuine msg1 authenticates");
assert_eq!(
plain.greatest(stranger.canonical()),
Some(stranger.nth_timestamp(1)),
"the record is provisional but real while the chain lives"
);
plain.ep.reject(now2, id);
let _ = plain.drain();
assert_eq!(
plain.greatest(stranger.canonical()),
None,
"§17.1 mitigation (i): every other end-without-accepting reverts"
);
}
#[test]
fn the_pending_branch_loser_cancels_the_pending_and_installs_as_responder() {
let now = t0();
let (mut local, mut peer) = sides(now, false);
let (intro, pending_conn, _ours) = ordinary_ordering(now, &mut local, &mut peer);
let accepted = local.ep.accept(now, intro);
let d = local.drain();
let (new_conn, _c) = accepted.expect("§6.4: the tie-break loser accepts");
assert_ne!(
new_conn, pending_conn,
"§6.4: the accept is an ordinary fresh install, not the pending's \
connection — the pending was cancelled, not completed"
);
let (to, data) = d.one_transmit();
assert_eq!(to, peer.addr, "§5.6: anchored at the msg1 source");
assert_eq!(data.len(), RESP_PACKET_LEN);
assert_eq!(data[0], PKT_HANDSHAKE_RESP);
assert_eq!(
d.failures(),
vec![(pending_conn, ConnectError::AlreadyConnected)],
"§6.4:1412-1413: the cancelled pending's `Connecting` resolves \
`Err(ConnectError::AlreadyConnected)` — exactly once"
);
assert!(
d.installs().is_empty(),
"the accept's connection is returned, not installed: §16.4 emits \
`ToConnection` only for a `connect()`-created connection"
);
assert_eq!(
local.basis(peer.canonical()),
Some(Some(peer.nth_timestamp(1))),
"§17.4: we responded, at that initiation's timestamp"
);
assert!(
!local.hints().contains(&peer.addr),
"§17.4: the cancelled pending contributes no hint"
);
let d = local.timeout(now + past_giveup());
assert!(!d.timed_out(), "there is no pending left to give up on");
}
fn ordinary_api_ordering(local_is_winner: bool) {
let now = t0();
let (mut local, mut peer) = sides(now, local_is_winner);
let (peer_conn, d) = peer.dial(now, local.addr, &local.public_static);
let (to, msg1_peer) = d.one_transmit();
assert_eq!(to, local.addr);
let d = local.feed(now, peer.addr, &msg1_peer);
let (intro, _) = d.one_intro();
let claimed = local.ep.read_identity(now, intro).expect("§6.1 stage 1");
assert_eq!(claimed.as_ref(), peer.canonical());
let (local_conn, d) = local.dial(now, peer.addr, &peer.public_static);
let (to, msg1_local) = d.one_transmit();
assert_eq!(to, peer.addr);
let dp = peer.feed(now, local.addr, &msg1_local);
local
.ep
.authenticate(now, intro, &())
.expect("a genuine crossing msg1 authenticates");
let accepted = local.ep.accept(now, intro);
let dl = local.drain();
if local_is_winner {
assert_eq!(
accepted.err(),
Some(AcceptError::Stale),
"§6.4: the winner refuses"
);
assert!(dl.transmits().is_empty() && dl.installs().is_empty());
assert_eq!(
dp.installs(),
vec![peer_conn],
"§6.6 step 4: the loser's admission completes its own Connecting"
);
let (to, msg2) = dp.one_transmit();
assert_eq!(to, local.addr, "§5.6: anchored at our msg1's source");
assert_eq!(msg2.len(), RESP_PACKET_LEN);
let d = local.feed(now, peer.addr, &msg2);
assert_eq!(
d.installs(),
vec![local_conn],
"§6.7: the winner's own outbound completes, on its own connection"
);
} else {
let (_new_conn, _c) = accepted.expect("§6.4: the loser accepts");
let (to, msg2) = dl.one_transmit();
assert_eq!(to, peer.addr);
assert_eq!(msg2.len(), RESP_PACKET_LEN);
assert!(
dp.is_silent(),
"§6.6 step 3: the winner drops our msg1 silently, got {:?}",
dp.outs
);
assert_eq!(
peer.greatest(local.canonical()),
Some(local.nth_timestamp(1)),
"§6.7: and records its timestamp anyway"
);
let d = peer.feed(now, local.addr, &msg2);
assert_eq!(
d.installs(),
vec![peer_conn],
"§6.7: the winner's own outbound completes, on its own connection"
);
}
let (winner_side, loser_side) = if local_is_winner {
(&local, &peer)
} else {
(&peer, &local)
};
assert_eq!(
winner_side.basis(loser_side.canonical()),
Some(None),
"§17.4 / §6.7: the tie-break winner is the connection initiator"
);
assert!(
matches!(loser_side.basis(winner_side.canonical()), Some(Some(_))),
"§17.4: the loser installed as responder"
);
assert!(
local.hints().is_empty() && peer.hints().is_empty(),
"§17.4: nothing is dialling any more — local {:?}, peer {:?}",
local.hints(),
peer.hints()
);
let late = now + past_giveup();
let dl = local.timeout(late);
let dp = peer.timeout(late);
assert!(
!dl.timed_out(),
"ruling 91: the pre-slice-4 core ends here with `TimedOut` on this \
side (local_is_winner = {local_is_winner}), got {:?}",
dl.failures()
);
assert!(
!dp.timed_out(),
"ruling 91: and with `TimedOut` on the other side too, got {:?}",
dp.failures()
);
}
#[test]
fn the_ordinary_api_ordering_completes_both_sides_when_we_win() {
ordinary_api_ordering(true);
}
#[test]
fn the_ordinary_api_ordering_completes_both_sides_when_we_lose() {
ordinary_api_ordering(false);
}
#[test]
fn the_ordinary_api_ordering_yields_exactly_one_resolution_per_dial() {
for local_is_winner in [true, false] {
let now = t0();
let (mut local, mut peer) = sides(now, local_is_winner);
let (peer_conn, d) = peer.dial(now, local.addr, &local.public_static);
let (_, msg1_peer) = d.one_transmit();
let d = local.feed(now, peer.addr, &msg1_peer);
let (intro, _) = d.one_intro();
local.ep.read_identity(now, intro).expect("stage 1");
let (local_conn, d) = local.dial(now, peer.addr, &peer.public_static);
let (_, msg1_local) = d.one_transmit();
let mut local_events = Vec::new();
let mut peer_events = Vec::new();
let dp = peer.feed(now, local.addr, &msg1_local);
peer_events.extend(resolutions(&dp, peer_conn));
local.ep.authenticate(now, intro, &()).expect("genuine");
let accepted = local.ep.accept(now, intro).is_ok();
let dl = local.drain();
local_events.extend(resolutions(&dl, local_conn));
for (to, data) in dl.transmits() {
if data.len() == RESP_PACKET_LEN {
assert_eq!(to, peer.addr);
let d = peer.feed(now, local.addr, &data);
peer_events.extend(resolutions(&d, peer_conn));
}
}
for (to, data) in dp.transmits() {
if data.len() == RESP_PACKET_LEN {
assert_eq!(to, local.addr);
let d = local.feed(now, peer.addr, &data);
local_events.extend(resolutions(&d, local_conn));
}
}
assert_eq!(
local_events.len(),
1,
"§6.7: connect resolution is edge-triggered exactly once per \
connection lifecycle (local_is_winner = {local_is_winner}), got \
{local_events:?}"
);
assert_eq!(
peer_events.len(),
1,
"and once on the peer, got {peer_events:?}"
);
assert!(local.basis(peer.canonical()).is_some());
assert!(peer.basis(local.canonical()).is_some());
assert_eq!(
accepted, !local_is_winner,
"§6.4: the winner refuses the accept and the loser takes it"
);
}
}
#[derive(Debug, PartialEq, Eq)]
enum Resolution {
Installed,
Failed(ConnectError),
}
fn resolutions(d: &Drained, conn: ConnectionId) -> Vec<Resolution> {
let mut v: Vec<Resolution> = d
.installs()
.into_iter()
.filter(|c| *c == conn)
.map(|_| Resolution::Installed)
.collect();
v.extend(
d.failures()
.into_iter()
.filter(|(c, _)| *c == conn)
.map(|(_, e)| Resolution::Failed(e)),
);
v
}
#[test]
fn a_minted_but_unattempted_pending_still_yields_one_connection_for_one_static() {
for local_is_winner in [true, false] {
let now = t0();
let (mut local, mut peer) = sides(now, local_is_winner);
let msg1 = real_msg1(&mut peer, now, &local);
let conn = local.mint_only(now, peer.addr, &peer.public_static);
let _ = local.drain();
let d = local.feed(now, peer.addr, &msg1);
let mut resolved = resolutions(&d, conn);
if let Some((id, _)) = d.intros().first().copied() {
if local.ep.read_identity(now, id).is_ok()
&& local.ep.authenticate(now, id, &()).is_ok()
&& let Ok((accept_conn, _c)) = local.ep.accept(now, id)
{
assert_ne!(accept_conn, conn, "an accept never returns the dial's id");
}
let d = local.drain();
resolved.extend(resolutions(&d, conn));
}
assert!(
local.basis(peer.canonical()).is_some(),
"§16.1: exactly one row for that static, whichever route ran \
(local_is_winner = {local_is_winner})"
);
assert!(
resolved.len() <= 1,
"§6.7: a dial resolves at most once, got {resolved:?}"
);
}
}
#[test]
fn the_staged_guard_rejection_is_traced_under_policy() {
use crate::testutil::Capture;
let now = t0();
let (mut local, mut peer) = sides(now, true);
let first = real_msg1(&mut peer, now, &local);
let second = {
let d = peer.timeout(now + past_retransmit());
let (_, data) = d.one_transmit();
data
};
assert_ne!(first, second, "fixture check: two distinct initiations");
let d = local.feed(now, v4(9, 1), &second);
let (newer, _) = d.one_intro();
local.ep.read_identity(now, newer).expect("readable");
let _ = local.drain();
local
.ep
.authenticate(now, newer, &())
.expect("the newer initiation authenticates");
let _ = local.drain();
assert_eq!(
local.greatest(peer.canonical()),
Some(peer.nth_timestamp(2)),
"fixture check: the newer initiation is recorded, so the older one \
below is a genuine replay rather than a first sighting"
);
let capture = Capture::install();
let d = local.feed(now, v4(9, 2), &first);
let (older, _) = d.one_intro();
local.ep.read_identity(now, older).expect("readable");
let _ = local.drain();
let outcome = local.ep.authenticate(now, older, &());
let _ = local.drain();
assert_eq!(
outcome,
Err(AuthError::Replay),
"fixture check: the older initiation must die at §17.1's guard, or \
the assertions below are measuring a path that never ran"
);
let traced = capture.with_target("slither::policy");
let replays: Vec<_> = traced
.iter()
.filter(|e| e.field("event") == Some("guard_replay"))
.collect();
assert_eq!(
replays.len(),
1,
"§18.2's `slither::policy` row carries guard rejections, and the \
staged path must emit one per rejection. Captured on this target: \
{traced:?}"
);
}
#[test]
fn the_accept_path_arming_is_traced_under_roam_without_the_challenge() {
use crate::testutil::Capture;
let t = t0();
let (mut b, mut a) = sides(t, true);
let msg1 = real_msg1(&mut a, t, &b);
let capture = Capture::install();
let id = b.feed(t, a.addr, &msg1).one_intro().0;
b.ep.read_identity(t, id).expect("readable");
let _ = b.drain();
b.ep.authenticate(t, id, &()).expect("authenticates");
let _ = b.drain();
let _ = b.ep.accept(t, id).expect("a fresh static accepts");
let _ = b.drain();
let armed: Vec<_> = capture
.with_target("slither::roam")
.into_iter()
.filter(|e| e.field("event") == Some("path_challenge_armed"))
.collect();
assert_eq!(
armed.len(),
1,
"§18.2's `slither::roam` row carries the challenge drawn at each arming, and an accept arms exactly one budget"
);
assert_eq!(
armed[0].field("arming"),
Some("accept"),
"the two armings must be tellable apart"
);
for (name, value) in &armed[0].fields {
assert!(
!(value.len() >= 16 && value.chars().all(|c| c.is_ascii_hexdigit())),
"the field `{name}` looks like the challenge itself ({value}). §7.3's budget is lifted by echoing that value: a log that carries it hands the validation to anyone who can read the log"
);
}
}