Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,6 @@ uuid = { version = "1.8", features = ["v4"] }
# mDNS for WiFi-Direct discovery
mdns-sd = "0.11"

# HTTP Client for RPC
reqwest = { version = "0.11", features = ["json"] }



[target.'cfg(target_os = "linux")'.dependencies]
dbus = { version = "0.9.11", features = ["vendored"] }
Expand Down
44 changes: 0 additions & 44 deletions src/relay/rpc_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,50 +91,6 @@ struct ResultCodes {
transaction: Option<String>,
}

impl RpcClient {
/// Create a new RPC client with the given endpoint URL
///
/// # Example
/// ```
/// use stellarconduit_core::relay::rpc_client::RpcClient;
///
/// let client = RpcClient::new("https://soroban-testnet.stellar.org");
/// ```
pub fn new(endpoint: impl Into<String>) -> Self {
Self {
endpoint: endpoint.into(),
http: Client::new(),
}
}

/// Submit a base64-encoded XDR transaction to the Soroban network.
///
/// # Arguments
/// * `tx_xdr` - The base64-encoded Stellar transaction XDR
///
/// # Returns
/// * `Ok(String)` - The transaction hash on successful submission
/// * `Err(RpcError)` - RPC error details if submission fails
///
/// # Example
/// ```no_run
/// # use stellarconduit_core::relay::rpc_client::RpcClient;
/// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
/// let client = RpcClient::new("https://soroban-testnet.stellar.org");
/// let tx_hash = client.submit_transaction("AAAAAgAAAAD...").await?;
/// println!("Transaction hash: {}", tx_hash);
/// # Ok(())
/// # }
/// ```
pub async fn submit_transaction(&self, tx_xdr: &str) -> Result<String, RpcError> {
let request = SorobanRpcRequest {
jsonrpc: "2.0",
id: 1,
method: "sendTransaction",
params: SendTxParams {
transaction: tx_xdr.to_string(),
},
};
// ---------- async trait impl ----------

#[async_trait]
Expand Down
73 changes: 73 additions & 0 deletions src/transport/unified.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1322,6 +1322,79 @@ mod tests {
assert_eq!(mgr.peer_count.load(Ordering::SeqCst), 0);
}

#[tokio::test]
async fn test_notify_mac_rotated_drops_ble_keeps_wifi() {
use crate::transport::ble_transport::BleCentral;

// Minimal mock that reports as a WiFi-Direct connection. WiFi-Direct
// connections do not reference the BLE MAC, so they must survive a
// MAC rotation.
struct MockWifiConnection {
peer: PeerIdentity,
}

#[async_trait]
impl Connection for MockWifiConnection {
fn remote_peer(&self) -> PeerIdentity {
self.peer.clone()
}
fn transport_type(&self) -> TransportType {
TransportType::WifiDirect
}
fn state(&self) -> ConnectionState {
ConnectionState::Connected
}
async fn connect(&mut self) -> Result<(), TransportError> {
Ok(())
}
async fn send(&mut self, _msg: ProtocolMessage) -> Result<(), TransportError> {
Ok(())
}
async fn recv(&mut self) -> Result<ProtocolMessage, TransportError> {
Err(TransportError::BrokenPipe)
}
async fn disconnect(&mut self) -> Result<(), TransportError> {
Ok(())
}
}

let mut mgr = TransportManager::new(TransportPreference::Auto);
let ble_peer = peer(0x11);
let wifi_peer = peer(0x22);

// One BLE connection and one WiFi-Direct connection.
let ble_conn = Box::new(BleCentral::new(ble_peer.clone()));
mgr.active_connections.insert(ble_peer.pubkey, ble_conn);
mgr.peer_count.fetch_add(1, Ordering::SeqCst);

let wifi_conn = Box::new(MockWifiConnection {
peer: wifi_peer.clone(),
});
mgr.active_connections.insert(wifi_peer.pubkey, wifi_conn);
mgr.peer_count.fetch_add(1, Ordering::SeqCst);

assert_eq!(mgr.connection_count(), 2);

let new_mac = [0xAA, 0x02, 0x00, 0x00, 0x00, 0x00];
mgr.notify_mac_rotated(new_mac).await;

// The BLE connection is dropped; the WiFi-Direct connection is retained.
assert_eq!(
mgr.connection_count(),
1,
"WiFi-Direct connection should survive a MAC rotation"
);
assert!(
!mgr.active_connections.contains_key(&ble_peer.pubkey),
"BLE connection should be dropped after MAC rotation"
);
assert!(
mgr.active_connections.contains_key(&wifi_peer.pubkey),
"WiFi-Direct connection should remain after MAC rotation"
);
assert_eq!(mgr.peer_count.load(Ordering::SeqCst), 1);
}

#[tokio::test]
async fn test_power_tick_includes_mac_rotated_flag() {
use crate::transport::ble_transport::BleCentral;
Expand Down
Loading