Pushes name the peer by ticket, and an allowance can confirm its push

PeerAllowPush and Push take a blob ticket the peer issued as well as a
NodeId; the ticket's addresses are remembered, so the push dials
directly. A peer allowed to push may observe too: the sender confirms a
push by observing it, and without that every allowance-only push
reported failure though it had landed. The allowance test now fails
instead of skipping on anything but an unreachable peer.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Bendik Aagaard Lynghaug
2026-10-03 13:29:03 +02:00
co-authored by Claude Opus 5.5
parent 4d9985c9cb
commit c2b9167e1e
5 changed files with 56 additions and 14 deletions
+16 -4
View File
@@ -437,7 +437,6 @@ fn push_allowance_is_enough_and_is_not_trust() {
let mut client_a = support::Client::connect(&a.socket);
let mut client_b = support::Client::connect(&b.socket);
let id_a = node_id(&mut client_a);
let id_b = node_id(&mut client_b);
let dir = tempfile::tempdir().unwrap();
let src = dir.path().join("voice.bin");
@@ -446,7 +445,16 @@ fn push_allowance_is_enough_and_is_not_trust() {
let hash = add_file(&mut client_a, &src);
pin(&mut client_a, &hash, false);
assert!(client_a.request(&Request::PeerAllowPush { node_id: id_b.clone(), ttl_secs: 600 }).ok);
// A knows B by a ticket B handed out (as redoal peers do), not by
// its bare node id.
let b_src = dir.path().join("b-own.bin");
std::fs::write(&b_src, vec![1u8; 1_000]).unwrap();
let b_hash = add_file(&mut client_b, &b_src);
let b_ticket = match client_b.request(&Request::TicketExport { hash: b_hash }).data {
Some(ResponseData::Ticket { ticket }) => ticket,
other => panic!("unexpected ticket reply: {other:?}"),
};
assert!(client_a.request(&Request::PeerAllowPush { node_id: b_ticket.clone(), ttl_secs: 600 }).ok);
assert!(client_b.request(&Request::PeerAllowPush { node_id: id_a, ttl_secs: 600 }).ok);
match client_a.request(&Request::PeerList {}).data {
Some(ResponseData::Peers { peers }) => assert!(peers.is_empty(), "an allowance is not trust: {peers:?}"),
@@ -456,14 +464,18 @@ fn push_allowance_is_enough_and_is_not_trust() {
// The peer's address arrives by mdns; retry until it does.
let deadline = Instant::now() + Duration::from_secs(30);
let reply = loop {
let reply = client_a.request(&Request::Push { hash: hash.clone(), node_id: id_b.clone() });
let reply = client_a.request(&Request::Push { hash: hash.clone(), node_id: b_ticket.clone() });
if reply.ok || Instant::now() > deadline {
break reply;
}
std::thread::sleep(Duration::from_millis(500));
};
if !reply.ok {
eprintln!("SKIP: push never reached the peer (multicast unavailable?): {:?}", reply.error);
let message = reply.error.map(|e| e.message).unwrap_or_default();
// Only an unreachable peer is the environment's fault; any other
// refusal is a real failure.
assert!(message.contains("connect"), "push failed: {message}");
eprintln!("SKIP: push never reached the peer (multicast unavailable?): {message}");
return;
}
assert!(wait_complete(&b.socket, &hash, Duration::from_secs(60)), "pushed content not complete on receiver");