Skip to content

Commit 1a74367

Browse files
authored
Merge pull request #1184 from TheBlueMatt/2021-11-c-bindings-tweaks
C Bindings Compatibility Tweaks
2 parents 937403e + 3539f27 commit 1a74367

File tree

6 files changed

+194
-86
lines changed

6 files changed

+194
-86
lines changed

.github/workflows/build.yml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,14 @@ jobs:
123123
cargo test --verbose --color always -p lightning
124124
cargo test --verbose --color always -p lightning-invoice
125125
cargo build --verbose --color always -p lightning-persister
126+
cargo build --verbose --color always -p lightning-background-processor
127+
- name: Test C Bindings Modifications on Rust ${{ matrix.toolchain }}
128+
if: "! matrix.build-net-tokio"
129+
run: |
130+
RUSTFLAGS="--cfg=c_bindings" cargo test --verbose --color always -p lightning
131+
RUSTFLAGS="--cfg=c_bindings" cargo test --verbose --color always -p lightning-invoice
132+
RUSTFLAGS="--cfg=c_bindings" cargo build --verbose --color always -p lightning-persister
133+
RUSTFLAGS="--cfg=c_bindings" cargo build --verbose --color always -p lightning-background-processor
126134
- name: Test Block Sync Clients on Rust ${{ matrix.toolchain }} with features
127135
if: "matrix.build-net-tokio && !matrix.coverage"
128136
run: |

lightning-invoice/src/payment.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
//! # use lightning::routing::router::{Route, RouteHop, RouteParameters};
3737
//! # use lightning::util::events::{Event, EventHandler, EventsProvider};
3838
//! # use lightning::util::logger::{Logger, Record};
39+
//! # use lightning::util::ser::{Writeable, Writer};
3940
//! # use lightning_invoice::Invoice;
4041
//! # use lightning_invoice::payment::{InvoicePayer, Payer, RetryAttempts, Router};
4142
//! # use secp256k1::key::PublicKey;
@@ -71,6 +72,9 @@
7172
//! # }
7273
//! #
7374
//! # struct FakeScorer {};
75+
//! # impl Writeable for FakeScorer {
76+
//! # fn write<W: Writer>(&self, w: &mut W) -> Result<(), std::io::Error> { unimplemented!(); }
77+
//! # }
7478
//! # impl Score for FakeScorer {
7579
//! # fn channel_penalty_msat(
7680
//! # &self, _short_channel_id: u64, _send_amt: u64, _chan_amt: Option<u64>, _source: &NodeId, _target: &NodeId
@@ -1224,6 +1228,10 @@ mod tests {
12241228
}
12251229
}
12261230

1231+
#[cfg(c_bindings)]
1232+
impl lightning::util::ser::Writeable for TestScorer {
1233+
fn write<W: lightning::util::ser::Writer>(&self, _: &mut W) -> Result<(), std::io::Error> { unreachable!(); }
1234+
}
12271235
impl Score for TestScorer {
12281236
fn channel_penalty_msat(
12291237
&self, _short_channel_id: u64, _send_amt: u64, _chan_amt: Option<u64>, _source: &NodeId, _target: &NodeId

lightning/src/routing/router.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1488,6 +1488,8 @@ mod tests {
14881488
use ln::channelmanager;
14891489
use util::test_utils;
14901490
use util::ser::Writeable;
1491+
#[cfg(c_bindings)]
1492+
use util::ser::Writer;
14911493

14921494
use bitcoin::hashes::sha256d::Hash as Sha256dHash;
14931495
use bitcoin::hashes::Hash;
@@ -4653,6 +4655,10 @@ mod tests {
46534655
short_channel_id: u64,
46544656
}
46554657

4658+
#[cfg(c_bindings)]
4659+
impl Writeable for BadChannelScorer {
4660+
fn write<W: Writer>(&self, _w: &mut W) -> Result<(), ::io::Error> { unimplemented!() }
4661+
}
46564662
impl Score for BadChannelScorer {
46574663
fn channel_penalty_msat(&self, short_channel_id: u64, _send_amt: u64, _chan_amt: Option<u64>, _source: &NodeId, _target: &NodeId) -> u64 {
46584664
if short_channel_id == self.short_channel_id { u64::max_value() } else { 0 }
@@ -4665,6 +4671,11 @@ mod tests {
46654671
node_id: NodeId,
46664672
}
46674673

4674+
#[cfg(c_bindings)]
4675+
impl Writeable for BadNodeScorer {
4676+
fn write<W: Writer>(&self, _w: &mut W) -> Result<(), ::io::Error> { unimplemented!() }
4677+
}
4678+
46684679
impl Score for BadNodeScorer {
46694680
fn channel_penalty_msat(&self, _short_channel_id: u64, _send_amt: u64, _chan_amt: Option<u64>, _source: &NodeId, target: &NodeId) -> u64 {
46704681
if *target == self.node_id { u64::max_value() } else { 0 }

lightning/src/routing/scoring.rs

Lines changed: 146 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,8 @@
4646
//!
4747
//! # Note
4848
//!
49-
//! If persisting [`Scorer`], it must be restored using the same [`Time`] parameterization. Using a
50-
//! different type results in undefined behavior. Specifically, persisting when built with feature
51-
//! `no-std` and restoring without it, or vice versa, uses different types and thus is undefined.
49+
//! Persisting when built with feature `no-std` and restoring without it, or vice versa, uses
50+
//! different types and thus is undefined.
5251
//!
5352
//! [`find_route`]: crate::routing::router::find_route
5453
@@ -59,14 +58,27 @@ use util::ser::{Readable, Writeable, Writer};
5958

6059
use prelude::*;
6160
use core::cell::{RefCell, RefMut};
62-
use core::ops::{DerefMut, Sub};
61+
use core::ops::DerefMut;
6362
use core::time::Duration;
64-
use io::{self, Read}; use sync::{Mutex, MutexGuard};
63+
use io::{self, Read};
64+
use sync::{Mutex, MutexGuard};
6565

66+
/// We define Score ever-so-slightly differently based on whether we are being built for C bindings
67+
/// or not. For users, `LockableScore` must somehow be writeable to disk. For Rust users, this is
68+
/// no problem - you move a `Score` that implements `Writeable` into a `Mutex`, lock it, and now
69+
/// you have the original, concrete, `Score` type, which presumably implements `Writeable`.
70+
///
71+
/// For C users, once you've moved the `Score` into a `LockableScore` all you have after locking it
72+
/// is an opaque trait object with an opaque pointer with no type info. Users could take the unsafe
73+
/// approach of blindly casting that opaque pointer to a concrete type and calling `Writeable` from
74+
/// there, but other languages downstream of the C bindings (e.g. Java) can't even do that.
75+
/// Instead, we really want `Score` and `LockableScore` to implement `Writeable` directly, which we
76+
/// do here by defining `Score` differently for `cfg(c_bindings)`.
77+
macro_rules! define_score { ($($supertrait: path)*) => {
6678
/// An interface used to score payment channels for path finding.
6779
///
6880
/// Scoring is in terms of fees willing to be paid in order to avoid routing through a channel.
69-
pub trait Score {
81+
pub trait Score $(: $supertrait)* {
7082
/// Returns the fee in msats willing to be paid to avoid routing `send_amt_msat` through the
7183
/// given channel in the direction from `source` to `target`.
7284
///
@@ -85,6 +97,22 @@ pub trait Score {
8597
fn payment_path_failed(&mut self, path: &[&RouteHop], short_channel_id: u64);
8698
}
8799

100+
impl<S: Score, T: DerefMut<Target=S> $(+ $supertrait)*> Score for T {
101+
fn channel_penalty_msat(&self, short_channel_id: u64, send_amt_msat: u64, channel_capacity_msat: Option<u64>, source: &NodeId, target: &NodeId) -> u64 {
102+
self.deref().channel_penalty_msat(short_channel_id, send_amt_msat, channel_capacity_msat, source, target)
103+
}
104+
105+
fn payment_path_failed(&mut self, path: &[&RouteHop], short_channel_id: u64) {
106+
self.deref_mut().payment_path_failed(path, short_channel_id)
107+
}
108+
}
109+
} }
110+
111+
#[cfg(c_bindings)]
112+
define_score!(Writeable);
113+
#[cfg(not(c_bindings))]
114+
define_score!();
115+
88116
/// A scorer that is accessed under a lock.
89117
///
90118
/// Needed so that calls to [`Score::channel_penalty_msat`] in [`find_route`] can be made while
@@ -101,6 +129,7 @@ pub trait LockableScore<'a> {
101129
fn lock(&'a self) -> Self::Locked;
102130
}
103131

132+
/// (C-not exported)
104133
impl<'a, T: 'a + Score> LockableScore<'a> for Mutex<T> {
105134
type Locked = MutexGuard<'a, T>;
106135

@@ -117,13 +146,34 @@ impl<'a, T: 'a + Score> LockableScore<'a> for RefCell<T> {
117146
}
118147
}
119148

120-
impl<S: Score, T: DerefMut<Target=S>> Score for T {
121-
fn channel_penalty_msat(&self, short_channel_id: u64, send_amt_msat: u64, channel_capacity_msat: Option<u64>, source: &NodeId, target: &NodeId) -> u64 {
122-
self.deref().channel_penalty_msat(short_channel_id, send_amt_msat, channel_capacity_msat, source, target)
149+
#[cfg(c_bindings)]
150+
/// A concrete implementation of [`LockableScore`] which supports multi-threading.
151+
pub struct MultiThreadedLockableScore<S: Score> {
152+
score: Mutex<S>,
153+
}
154+
#[cfg(c_bindings)]
155+
/// (C-not exported)
156+
impl<'a, T: Score + 'a> LockableScore<'a> for MultiThreadedLockableScore<T> {
157+
type Locked = MutexGuard<'a, T>;
158+
159+
fn lock(&'a self) -> MutexGuard<'a, T> {
160+
Mutex::lock(&self.score).unwrap()
161+
}
162+
}
163+
164+
#[cfg(c_bindings)]
165+
/// (C-not exported)
166+
impl<'a, T: Writeable> Writeable for RefMut<'a, T> {
167+
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), io::Error> {
168+
T::write(&**self, writer)
123169
}
170+
}
124171

125-
fn payment_path_failed(&mut self, path: &[&RouteHop], short_channel_id: u64) {
126-
self.deref_mut().payment_path_failed(path, short_channel_id)
172+
#[cfg(c_bindings)]
173+
/// (C-not exported)
174+
impl<'a, S: Writeable> Writeable for MutexGuard<'a, S> {
175+
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), io::Error> {
176+
S::write(&**self, writer)
127177
}
128178
}
129179

@@ -135,23 +185,33 @@ impl<S: Score, T: DerefMut<Target=S>> Score for T {
135185
/// See [module-level documentation] for usage.
136186
///
137187
/// [module-level documentation]: crate::routing::scoring
138-
pub type Scorer = ScorerUsingTime::<DefaultTime>;
139-
140-
/// Time used by [`Scorer`].
141188
#[cfg(not(feature = "no-std"))]
142-
pub type DefaultTime = std::time::Instant;
143-
144-
/// Time used by [`Scorer`].
189+
pub type Scorer = ScorerUsingTime::<std::time::Instant>;
190+
/// [`Score`] implementation that provides reasonable default behavior.
191+
///
192+
/// Used to apply a fixed penalty to each channel, thus avoiding long paths when shorter paths with
193+
/// slightly higher fees are available. Will further penalize channels that fail to relay payments.
194+
///
195+
/// See [module-level documentation] for usage.
196+
///
197+
/// [module-level documentation]: crate::routing::scoring
145198
#[cfg(feature = "no-std")]
146-
pub type DefaultTime = Eternity;
199+
pub type Scorer = ScorerUsingTime::<time::Eternity>;
147200

148-
/// [`Score`] implementation parameterized by [`Time`].
201+
// Note that ideally we'd hide ScorerUsingTime from public view by sealing it as well, but rustdoc
202+
// doesn't handle this well - instead exposing a `Scorer` which has no trait implementation(s) or
203+
// methods at all.
204+
205+
/// [`Score`] implementation.
149206
///
150207
/// See [`Scorer`] for details.
151208
///
152209
/// # Note
153210
///
154-
/// Mixing [`Time`] types between serialization and deserialization results in undefined behavior.
211+
/// Mixing the `no-std` feature between serialization and deserialization results in undefined
212+
/// behavior.
213+
///
214+
/// (C-not exported) generally all users should use the [`Scorer`] type alias.
155215
pub struct ScorerUsingTime<T: Time> {
156216
params: ScoringParameters,
157217
// TODO: Remove entries of closed channels.
@@ -197,8 +257,8 @@ pub struct ScoringParameters {
197257
///
198258
/// # Note
199259
///
200-
/// When time is an [`Eternity`], as is default when enabling feature `no-std`, it will never
201-
/// elapse. Therefore, this penalty will never decay.
260+
/// When built with the `no-std` feature, time will never elapse. Therefore, this penalty will
261+
/// never decay.
202262
///
203263
/// [`failure_penalty_msat`]: Self::failure_penalty_msat
204264
pub failure_penalty_half_life: Duration,
@@ -223,20 +283,6 @@ struct ChannelFailure<T: Time> {
223283
last_failed: T,
224284
}
225285

226-
/// A measurement of time.
227-
pub trait Time: Sub<Duration, Output = Self> where Self: Sized {
228-
/// Returns an instance corresponding to the current moment.
229-
fn now() -> Self;
230-
231-
/// Returns the amount of time elapsed since `self` was created.
232-
fn elapsed(&self) -> Duration;
233-
234-
/// Returns the amount of time passed since the beginning of [`Time`].
235-
///
236-
/// Used during (de-)serialization.
237-
fn duration_since_epoch() -> Duration;
238-
}
239-
240286
impl<T: Time> ScorerUsingTime<T> {
241287
/// Creates a new scorer using the given scoring parameters.
242288
pub fn new(params: ScoringParameters) -> Self {
@@ -333,48 +379,6 @@ impl<T: Time> Score for ScorerUsingTime<T> {
333379
}
334380
}
335381

336-
#[cfg(not(feature = "no-std"))]
337-
impl Time for std::time::Instant {
338-
fn now() -> Self {
339-
std::time::Instant::now()
340-
}
341-
342-
fn duration_since_epoch() -> Duration {
343-
use std::time::SystemTime;
344-
SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap()
345-
}
346-
347-
fn elapsed(&self) -> Duration {
348-
std::time::Instant::elapsed(self)
349-
}
350-
}
351-
352-
/// A state in which time has no meaning.
353-
#[derive(Debug, PartialEq, Eq)]
354-
pub struct Eternity;
355-
356-
impl Time for Eternity {
357-
fn now() -> Self {
358-
Self
359-
}
360-
361-
fn duration_since_epoch() -> Duration {
362-
Duration::from_secs(0)
363-
}
364-
365-
fn elapsed(&self) -> Duration {
366-
Duration::from_secs(0)
367-
}
368-
}
369-
370-
impl Sub<Duration> for Eternity {
371-
type Output = Self;
372-
373-
fn sub(self, _other: Duration) -> Self {
374-
self
375-
}
376-
}
377-
378382
impl<T: Time> Writeable for ScorerUsingTime<T> {
379383
#[inline]
380384
fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
@@ -425,9 +429,72 @@ impl<T: Time> Readable for ChannelFailure<T> {
425429
}
426430
}
427431

432+
pub(crate) mod time {
433+
use core::ops::Sub;
434+
use core::time::Duration;
435+
/// A measurement of time.
436+
pub trait Time: Sub<Duration, Output = Self> where Self: Sized {
437+
/// Returns an instance corresponding to the current moment.
438+
fn now() -> Self;
439+
440+
/// Returns the amount of time elapsed since `self` was created.
441+
fn elapsed(&self) -> Duration;
442+
443+
/// Returns the amount of time passed since the beginning of [`Time`].
444+
///
445+
/// Used during (de-)serialization.
446+
fn duration_since_epoch() -> Duration;
447+
}
448+
449+
/// A state in which time has no meaning.
450+
#[derive(Debug, PartialEq, Eq)]
451+
pub struct Eternity;
452+
453+
#[cfg(not(feature = "no-std"))]
454+
impl Time for std::time::Instant {
455+
fn now() -> Self {
456+
std::time::Instant::now()
457+
}
458+
459+
fn duration_since_epoch() -> Duration {
460+
use std::time::SystemTime;
461+
SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap()
462+
}
463+
464+
fn elapsed(&self) -> Duration {
465+
std::time::Instant::elapsed(self)
466+
}
467+
}
468+
469+
impl Time for Eternity {
470+
fn now() -> Self {
471+
Self
472+
}
473+
474+
fn duration_since_epoch() -> Duration {
475+
Duration::from_secs(0)
476+
}
477+
478+
fn elapsed(&self) -> Duration {
479+
Duration::from_secs(0)
480+
}
481+
}
482+
483+
impl Sub<Duration> for Eternity {
484+
type Output = Self;
485+
486+
fn sub(self, _other: Duration) -> Self {
487+
self
488+
}
489+
}
490+
}
491+
492+
pub(crate) use self::time::Time;
493+
428494
#[cfg(test)]
429495
mod tests {
430-
use super::{Eternity, ScoringParameters, ScorerUsingTime, Time};
496+
use super::{ScoringParameters, ScorerUsingTime, Time};
497+
use super::time::Eternity;
431498

432499
use routing::scoring::Score;
433500
use routing::network_graph::NodeId;

0 commit comments

Comments
 (0)