From 1f2a0605bc3bf1d8814f7718b346da19bbb73b57 Mon Sep 17 00:00:00 2001
From: Mohan <86064887+binarybaron@users.noreply.github.com>
Date: Sat, 8 Nov 2025 17:48:15 +0100
Subject: [PATCH] refactor(bob): EventLoop concurrency (#642)
* progress
* fix race condition where EventLoopHandle::swap_handle would take forever if event loop was not running
* add trace statements in bob event loop, inform swarm about redials
* progress
* revamp of protocols/swap_setup, reliable error propagation, slowly getting this to work...
* some formatting
* fix react shengigans
* If a connection handler died which had an assigned swap setup request, notify the swarm that the request failed
* key inflight swap setup request by (PeerId, SwapID) instead of just peer id
* add min height to swap state page
* extract should_acknowledge_transfer_proof out of event loop, propagate swap setup errors to event loop with context
* add --trace to justfile
* remove docker_test_all.sh
* add back the correct connection_keep_alive swap_setup/alice.rs
* fix some memory leaks
* let swarm_setup behaviour instruct swarm to dial peer
* fmt
* reduce diff
* remove redial::Redialing
* add trace statements to swap_setup/bob.rs
* extract swap setup protocol itself into run_swap_setup
* make queues unbounded, small nitpicks
* do not buffer transfer proof acknowledgements
* prevent swap_setup/bob.rs from keeping all connections alive
* buffer transfer proofs
* do not redial ALL peers
* keep all connections alive with swap_setup/bob.rs
* add comment
---
justfile | 3 +-
.../components/pages/swap/swap/SwapWidget.tsx | 11 +-
swap-p2p/Cargo.toml | 2 +-
swap-p2p/src/futures_util.rs | 71 ++
swap-p2p/src/lib.rs | 1 +
swap-p2p/src/out_event/bob.rs | 8 +-
swap-p2p/src/protocols.rs | 1 +
swap-p2p/src/protocols/redial.rs | 205 ++++++
swap-p2p/src/protocols/swap_setup/bob.rs | 513 +++++++++++---
swap/src/cli.rs | 2 +-
swap/src/cli/api/request.rs | 17 +-
swap/src/cli/behaviour.rs | 5 +-
swap/src/cli/event_loop.rs | 652 ++++++++++++------
swap/src/common/tracing_util.rs | 7 +-
swap/src/network.rs | 2 +-
swap/src/network/redial.rs | 135 ----
swap/src/protocol/bob.rs | 6 +-
swap/src/protocol/bob/swap.rs | 6 +-
swap/tests/harness/mod.rs | 18 +-
19 files changed, 1158 insertions(+), 507 deletions(-)
create mode 100644 swap-p2p/src/futures_util.rs
create mode 100644 swap-p2p/src/protocols/redial.rs
delete mode 100644 swap/src/network/redial.rs
diff --git a/justfile b/justfile
index fd8801d9..8c5dc41e 100644
--- a/justfile
+++ b/justfile
@@ -80,7 +80,7 @@ swap:
# Run the asb on testnet
asb-testnet:
- ASB_DEV_ADDR_OUTPUT_PATH="$(pwd)/src-gui/.env.development" cargo run -p swap-asb --bin asb -- --testnet start --rpc-bind-port 9944 --rpc-bind-host 0.0.0.0
+ ASB_DEV_ADDR_OUTPUT_PATH="$(pwd)/src-gui/.env.development" cargo run -p swap-asb --bin asb -- --testnet --trace start --rpc-bind-port 9944 --rpc-bind-host 0.0.0.0
# Launch the ASB controller REPL against a local testnet ASB instance
asb-testnet-controller:
@@ -140,3 +140,4 @@ code2prompt_single_crate crate:
prepare-windows-build:
cd dev-scripts && ./ubuntu_build_x86_86-w64-mingw32-gcc.sh
+
diff --git a/src-gui/src/renderer/components/pages/swap/swap/SwapWidget.tsx b/src-gui/src/renderer/components/pages/swap/swap/SwapWidget.tsx
index 03741cb2..04118063 100644
--- a/src-gui/src/renderer/components/pages/swap/swap/SwapWidget.tsx
+++ b/src-gui/src/renderer/components/pages/swap/swap/SwapWidget.tsx
@@ -52,7 +52,16 @@ export default function SwapWidget() {
flex: 1,
}}
>
-
+
+
+
{swap.state !== null && (
<>
diff --git a/swap-p2p/Cargo.toml b/swap-p2p/Cargo.toml
index 54a0c095..2ef5b3cd 100644
--- a/swap-p2p/Cargo.toml
+++ b/swap-p2p/Cargo.toml
@@ -13,7 +13,7 @@ swap-machine = { path = "../swap-machine" }
swap-serde = { path = "../swap-serde" }
# Networking
-libp2p = { workspace = true, features = ["serde", "request-response", "rendezvous", "cbor", "json", "ping", "identify"] }
+libp2p = { workspace = true, features = ["serde", "request-response", "rendezvous", "cbor", "json", "identify", "ping"] }
# Serialization
asynchronous-codec = "0.7.0"
diff --git a/swap-p2p/src/futures_util.rs b/swap-p2p/src/futures_util.rs
new file mode 100644
index 00000000..ca222632
--- /dev/null
+++ b/swap-p2p/src/futures_util.rs
@@ -0,0 +1,71 @@
+use libp2p::futures::future::BoxFuture;
+use libp2p::futures::stream::{FuturesUnordered, StreamExt};
+use std::collections::HashSet;
+use std::hash::Hash;
+use std::task::{Context, Poll};
+
+/// A collection of futures with associated keys that can be checked for presence
+/// before completion.
+///
+/// This combines a HashSet for key tracking with FuturesUnordered for efficient polling.
+/// The key is provided during insertion; the future only needs to yield the value.
+pub struct FuturesHashSet {
+ keys: HashSet,
+ futures: FuturesUnordered>,
+}
+
+impl FuturesHashSet {
+ pub fn new() -> Self {
+ Self {
+ keys: HashSet::new(),
+ futures: FuturesUnordered::new(),
+ }
+ }
+
+ /// Check if a future with the given key is already pending
+ pub fn contains_key(&self, key: &K) -> bool {
+ self.keys.contains(key)
+ }
+
+ /// Insert a new future with the given key.
+ /// The future should yield V; the key will be paired with it when it completes.
+ /// Returns true if the key was newly inserted, false if it was already present.
+ /// If false is returned, the future is not added.
+ pub fn insert(&mut self, key: K, future: BoxFuture<'static, V>) -> bool {
+ if self.keys.insert(key.clone()) {
+ let key_clone = key;
+ let wrapped = async move {
+ let value = future.await;
+ (key_clone, value)
+ };
+ self.futures.push(Box::pin(wrapped));
+ true
+ } else {
+ false
+ }
+ }
+
+ /// Poll for the next completed future.
+ /// When a future completes, its key is automatically removed from the tracking set.
+ pub fn poll_next_unpin(&mut self, cx: &mut Context) -> Poll