Skip to content

Commit 0e28bcb

Browse files
authored
Merge pull request #2141 from TheBlueMatt/2023-03-fuck-rust
Drop `futures` dependency from `lightning-block-sync`
2 parents 783e818 + 491100d commit 0e28bcb

File tree

5 files changed

+71
-21
lines changed

5 files changed

+71
-21
lines changed

lightning-background-processor/Cargo.toml

+1-2
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ all-features = true
1414
rustdoc-args = ["--cfg", "docsrs"]
1515

1616
[features]
17-
futures = [ "futures-util" ]
17+
futures = [ ]
1818
std = ["lightning/std", "lightning-rapid-gossip-sync/std"]
1919

2020
default = ["std"]
@@ -23,7 +23,6 @@ default = ["std"]
2323
bitcoin = { version = "0.29.0", default-features = false }
2424
lightning = { version = "0.0.114", path = "../lightning", default-features = false }
2525
lightning-rapid-gossip-sync = { version = "0.0.114", path = "../lightning-rapid-gossip-sync", default-features = false }
26-
futures-util = { version = "0.3", default-features = false, features = ["async-await-macro"], optional = true }
2726

2827
[dev-dependencies]
2928
lightning = { version = "0.0.114", path = "../lightning", features = ["_test_utils"] }

lightning-background-processor/src/lib.rs

+53-7
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
#![deny(private_intra_doc_links)]
88

99
#![deny(missing_docs)]
10-
#![deny(unsafe_code)]
10+
#![cfg_attr(not(feature = "futures"), deny(unsafe_code))]
1111

1212
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
1313

@@ -52,8 +52,6 @@ use std::thread::{self, JoinHandle};
5252
#[cfg(feature = "std")]
5353
use std::time::Instant;
5454

55-
#[cfg(feature = "futures")]
56-
use futures_util::{select_biased, future::FutureExt, task};
5755
#[cfg(not(feature = "std"))]
5856
use alloc::vec::Vec;
5957

@@ -384,6 +382,50 @@ macro_rules! define_run_body {
384382
} }
385383
}
386384

385+
#[cfg(feature = "futures")]
386+
pub(crate) mod futures_util {
387+
use core::future::Future;
388+
use core::task::{Poll, Waker, RawWaker, RawWakerVTable};
389+
use core::pin::Pin;
390+
use core::marker::Unpin;
391+
pub(crate) struct Selector<A: Future<Output=()> + Unpin, B: Future<Output=bool> + Unpin> {
392+
pub a: A,
393+
pub b: B,
394+
}
395+
pub(crate) enum SelectorOutput {
396+
A, B(bool),
397+
}
398+
399+
impl<A: Future<Output=()> + Unpin, B: Future<Output=bool> + Unpin> Future for Selector<A, B> {
400+
type Output = SelectorOutput;
401+
fn poll(mut self: Pin<&mut Self>, ctx: &mut core::task::Context<'_>) -> Poll<SelectorOutput> {
402+
match Pin::new(&mut self.a).poll(ctx) {
403+
Poll::Ready(()) => { return Poll::Ready(SelectorOutput::A); },
404+
Poll::Pending => {},
405+
}
406+
match Pin::new(&mut self.b).poll(ctx) {
407+
Poll::Ready(res) => { return Poll::Ready(SelectorOutput::B(res)); },
408+
Poll::Pending => {},
409+
}
410+
Poll::Pending
411+
}
412+
}
413+
414+
// If we want to poll a future without an async context to figure out if it has completed or
415+
// not without awaiting, we need a Waker, which needs a vtable...we fill it with dummy values
416+
// but sadly there's a good bit of boilerplate here.
417+
fn dummy_waker_clone(_: *const ()) -> RawWaker { RawWaker::new(core::ptr::null(), &DUMMY_WAKER_VTABLE) }
418+
fn dummy_waker_action(_: *const ()) { }
419+
420+
const DUMMY_WAKER_VTABLE: RawWakerVTable = RawWakerVTable::new(
421+
dummy_waker_clone, dummy_waker_action, dummy_waker_action, dummy_waker_action);
422+
pub(crate) fn dummy_waker() -> Waker { unsafe { Waker::from_raw(RawWaker::new(core::ptr::null(), &DUMMY_WAKER_VTABLE)) } }
423+
}
424+
#[cfg(feature = "futures")]
425+
use futures_util::{Selector, SelectorOutput, dummy_waker};
426+
#[cfg(feature = "futures")]
427+
use core::task;
428+
387429
/// Processes background events in a future.
388430
///
389431
/// `sleeper` should return a future which completes in the given amount of time and returns a
@@ -470,16 +512,20 @@ where
470512
chain_monitor, chain_monitor.process_pending_events_async(async_event_handler).await,
471513
channel_manager, channel_manager.process_pending_events_async(async_event_handler).await,
472514
gossip_sync, peer_manager, logger, scorer, should_break, {
473-
select_biased! {
474-
_ = channel_manager.get_persistable_update_future().fuse() => true,
475-
exit = sleeper(Duration::from_millis(100)).fuse() => {
515+
let fut = Selector {
516+
a: channel_manager.get_persistable_update_future(),
517+
b: sleeper(Duration::from_millis(100)),
518+
};
519+
match fut.await {
520+
SelectorOutput::A => true,
521+
SelectorOutput::B(exit) => {
476522
should_break = exit;
477523
false
478524
}
479525
}
480526
}, |t| sleeper(Duration::from_secs(t)),
481527
|fut: &mut SleepFuture, _| {
482-
let mut waker = task::noop_waker();
528+
let mut waker = dummy_waker();
483529
let mut ctx = task::Context::from_waker(&mut waker);
484530
core::pin::Pin::new(fut).poll(&mut ctx).is_ready()
485531
})

lightning-block-sync/Cargo.toml

-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ rpc-client = [ "serde_json", "chunked_transfer" ]
2020
[dependencies]
2121
bitcoin = "0.29.0"
2222
lightning = { version = "0.0.114", path = "../lightning" }
23-
futures-util = { version = "0.3" }
2423
tokio = { version = "1.0", features = [ "io-util", "net", "time" ], optional = true }
2524
serde_json = { version = "1.0", optional = true }
2625
chunked_transfer = { version = "1.4", optional = true }

lightning-block-sync/src/rest.rs

+8-6
Original file line numberDiff line numberDiff line change
@@ -7,32 +7,34 @@ use crate::http::{BinaryResponse, HttpEndpoint, HttpClient, JsonResponse};
77
use bitcoin::hash_types::BlockHash;
88
use bitcoin::hashes::hex::ToHex;
99

10-
use futures_util::lock::Mutex;
11-
1210
use std::convert::TryFrom;
1311
use std::convert::TryInto;
12+
use std::sync::Mutex;
1413

1514
/// A simple REST client for requesting resources using HTTP `GET`.
1615
pub struct RestClient {
1716
endpoint: HttpEndpoint,
18-
client: Mutex<HttpClient>,
17+
client: Mutex<Option<HttpClient>>,
1918
}
2019

2120
impl RestClient {
2221
/// Creates a new REST client connected to the given endpoint.
2322
///
2423
/// The endpoint should contain the REST path component (e.g., http://127.0.0.1:8332/rest).
2524
pub fn new(endpoint: HttpEndpoint) -> std::io::Result<Self> {
26-
let client = Mutex::new(HttpClient::connect(&endpoint)?);
27-
Ok(Self { endpoint, client })
25+
Ok(Self { endpoint, client: Mutex::new(None) })
2826
}
2927

3028
/// Requests a resource encoded in `F` format and interpreted as type `T`.
3129
pub async fn request_resource<F, T>(&self, resource_path: &str) -> std::io::Result<T>
3230
where F: TryFrom<Vec<u8>, Error = std::io::Error> + TryInto<T, Error = std::io::Error> {
3331
let host = format!("{}:{}", self.endpoint.host(), self.endpoint.port());
3432
let uri = format!("{}/{}", self.endpoint.path().trim_end_matches("/"), resource_path);
35-
self.client.lock().await.get::<F>(&uri, &host).await?.try_into()
33+
let mut client = if let Some(client) = self.client.lock().unwrap().take() { client }
34+
else { HttpClient::connect(&self.endpoint)? };
35+
let res = client.get::<F>(&uri, &host).await?.try_into();
36+
*self.client.lock().unwrap() = Some(client);
37+
res
3638
}
3739
}
3840

lightning-block-sync/src/rpc.rs

+9-5
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use crate::http::{HttpClient, HttpEndpoint, HttpError, JsonResponse};
77
use bitcoin::hash_types::BlockHash;
88
use bitcoin::hashes::hex::ToHex;
99

10-
use futures_util::lock::Mutex;
10+
use std::sync::Mutex;
1111

1212
use serde_json;
1313

@@ -41,7 +41,7 @@ impl Error for RpcError {}
4141
pub struct RpcClient {
4242
basic_auth: String,
4343
endpoint: HttpEndpoint,
44-
client: Mutex<HttpClient>,
44+
client: Mutex<Option<HttpClient>>,
4545
id: AtomicUsize,
4646
}
4747

@@ -50,11 +50,10 @@ impl RpcClient {
5050
/// credentials should be a base64 encoding of a user name and password joined by a colon, as is
5151
/// required for HTTP basic access authentication.
5252
pub fn new(credentials: &str, endpoint: HttpEndpoint) -> std::io::Result<Self> {
53-
let client = Mutex::new(HttpClient::connect(&endpoint)?);
5453
Ok(Self {
5554
basic_auth: "Basic ".to_string() + credentials,
5655
endpoint,
57-
client,
56+
client: Mutex::new(None),
5857
id: AtomicUsize::new(0),
5958
})
6059
}
@@ -73,7 +72,12 @@ impl RpcClient {
7372
"id": &self.id.fetch_add(1, Ordering::AcqRel).to_string()
7473
});
7574

76-
let mut response = match self.client.lock().await.post::<JsonResponse>(&uri, &host, &self.basic_auth, content).await {
75+
let mut client = if let Some(client) = self.client.lock().unwrap().take() { client }
76+
else { HttpClient::connect(&self.endpoint)? };
77+
let http_response = client.post::<JsonResponse>(&uri, &host, &self.basic_auth, content).await;
78+
*self.client.lock().unwrap() = Some(client);
79+
80+
let mut response = match http_response {
7781
Ok(JsonResponse(response)) => response,
7882
Err(e) if e.kind() == std::io::ErrorKind::Other => {
7983
match e.get_ref().unwrap().downcast_ref::<HttpError>() {

0 commit comments

Comments
 (0)