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
31 changes: 16 additions & 15 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -41,18 +41,18 @@ postgres = ["dep:tokio-postgres", "dep:native-tls", "dep:postgres-native-tls"]
#lightning-macros = { version = "0.2.0" }
#lightning-dns-resolver = { version = "0.3.0" }

lightning = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "506cb91f2e0fb87906188b79777bcf42595d3623", features = ["std"] }
lightning-types = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "506cb91f2e0fb87906188b79777bcf42595d3623" }
lightning-invoice = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "506cb91f2e0fb87906188b79777bcf42595d3623", features = ["std"] }
lightning-net-tokio = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "506cb91f2e0fb87906188b79777bcf42595d3623" }
lightning-persister = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "506cb91f2e0fb87906188b79777bcf42595d3623", features = ["tokio"] }
lightning-background-processor = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "506cb91f2e0fb87906188b79777bcf42595d3623" }
lightning-rapid-gossip-sync = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "506cb91f2e0fb87906188b79777bcf42595d3623" }
lightning-block-sync = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "506cb91f2e0fb87906188b79777bcf42595d3623", features = ["rest-client", "rpc-client", "tokio"] }
lightning-transaction-sync = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "506cb91f2e0fb87906188b79777bcf42595d3623", features = ["esplora-async-https", "time", "electrum-rustls-ring"] }
lightning-liquidity = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "506cb91f2e0fb87906188b79777bcf42595d3623", features = ["std"] }
lightning-macros = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "506cb91f2e0fb87906188b79777bcf42595d3623" }
lightning-dns-resolver = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "506cb91f2e0fb87906188b79777bcf42595d3623" }
lightning = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "9174965af9437196c527a9aa0df36bbcf050c8bb", features = ["std"] }
lightning-types = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "9174965af9437196c527a9aa0df36bbcf050c8bb" }
lightning-invoice = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "9174965af9437196c527a9aa0df36bbcf050c8bb", features = ["std"] }
lightning-net-tokio = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "9174965af9437196c527a9aa0df36bbcf050c8bb" }
lightning-persister = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "9174965af9437196c527a9aa0df36bbcf050c8bb", features = ["tokio"] }
lightning-background-processor = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "9174965af9437196c527a9aa0df36bbcf050c8bb" }
lightning-rapid-gossip-sync = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "9174965af9437196c527a9aa0df36bbcf050c8bb" }
lightning-block-sync = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "9174965af9437196c527a9aa0df36bbcf050c8bb", features = ["rest-client", "rpc-client", "tokio"] }
lightning-transaction-sync = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "9174965af9437196c527a9aa0df36bbcf050c8bb", features = ["esplora-async-https", "time", "electrum-rustls-ring"] }
lightning-liquidity = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "9174965af9437196c527a9aa0df36bbcf050c8bb", features = ["std"] }
lightning-macros = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "9174965af9437196c527a9aa0df36bbcf050c8bb" }
lightning-dns-resolver = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "9174965af9437196c527a9aa0df36bbcf050c8bb" }

bdk_chain = { version = "0.23.3", default-features = false, features = ["std"] }
bdk_esplora = { version = "0.22.2", default-features = false, features = ["async-https-rustls", "tokio"]}
Expand All @@ -71,6 +71,7 @@ getrandom = { version = "0.3", default-features = false }
chrono = { version = "0.4", default-features = false, features = ["clock"] }
tokio = { version = "1.39", default-features = false, features = [ "rt-multi-thread", "time", "sync", "macros", "net" ] }
esplora-client = { version = "0.12", default-features = false, features = ["tokio", "async-https-rustls"] }
ldk-esplora-client = { package = "esplora-client", version = "0.13", default-features = false, features = ["tokio", "async-https-rustls"] }
electrum-client = { version = "0.25", default-features = false, features = ["proxy", "use-rustls-ring"] }
libc = "0.2"
uniffi = { version = "0.29.5", features = ["build"], optional = true }
Expand All @@ -85,14 +86,14 @@ postgres-native-tls = { version = "0.5", default-features = false, features = ["
vss-client = { package = "vss-client-ng", version = "0.6" }
prost = { version = "0.11.6", default-features = false}
#bitcoin-payment-instructions = { version = "0.6" }
bitcoin-payment-instructions = { git = "https://github.com/tnull/bitcoin-payment-instructions", rev = "0e430be98c09540624a68a68022ee0551e86d1be" }
bitcoin-payment-instructions = { git = "https://github.com/tnull/bitcoin-payment-instructions", rev = "1d6ffaa8962391ddc84aeef98bd7439e55ccae9d" }

[target.'cfg(windows)'.dependencies]
winapi = { version = "0.3", features = ["winbase"] }

[dev-dependencies]
lightning = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "506cb91f2e0fb87906188b79777bcf42595d3623", features = ["std", "_test_utils"] }
lightning-persister = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "506cb91f2e0fb87906188b79777bcf42595d3623", features = ["tokio"] }
lightning = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "9174965af9437196c527a9aa0df36bbcf050c8bb", features = ["std", "_test_utils"] }
lightning-persister = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "9174965af9437196c527a9aa0df36bbcf050c8bb", features = ["tokio"] }
rand = { version = "0.9.2", default-features = false, features = ["std", "thread_rng", "os_rng"] }
proptest = "1.0.0"
regex = "1.5.6"
Expand Down
10 changes: 9 additions & 1 deletion src/chain/esplora.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,16 +56,24 @@ impl EsploraChainSource {
let mut client_builder = esplora_client::Builder::new(&server_url);
client_builder =
client_builder.timeout(sync_config.timeouts_config.per_request_timeout_secs as u64);
let mut ldk_client_builder = ldk_esplora_client::Builder::new(&server_url);
ldk_client_builder = ldk_client_builder.timeout(Duration::from_secs(
sync_config.timeouts_config.per_request_timeout_secs as u64,
));

for (header_name, header_value) in &headers {
client_builder = client_builder.header(header_name, header_value);
ldk_client_builder = ldk_client_builder.header(header_name, header_value);
}

let esplora_client = client_builder.build_async().map_err(|e| {
log_error!(logger, "Failed to build Esplora client: {}", e);
})?;
let ldk_esplora_client = ldk_client_builder.build_async().map_err(|e| {
log_error!(logger, "Failed to build LDK Esplora client: {}", e);
})?;
let tx_sync =
Arc::new(EsploraSyncClient::from_client(esplora_client.clone(), Arc::clone(&logger)));
Arc::new(EsploraSyncClient::from_client(ldk_esplora_client, Arc::clone(&logger)));

let onchain_wallet_sync_status = Mutex::new(WalletSyncStatus::Completed);
let lightning_wallet_sync_status = Mutex::new(WalletSyncStatus::Completed);
Expand Down
77 changes: 68 additions & 9 deletions src/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -196,9 +196,7 @@ pub enum Event {
/// transaction.
claim_from_onchain_tx: bool,
/// The final amount forwarded, in milli-satoshis, after the fee is deducted.
///
/// The caveat described above the `total_fee_earned_msat` field applies here as well.
outbound_amount_forwarded_msat: Option<u64>,
outbound_amount_forwarded_msat: u64,
},
/// A payment for a previously-registered payment hash has been received.
///
Expand Down Expand Up @@ -271,8 +269,10 @@ pub enum Event {
/// This will be `None` for events serialized by LDK Node v0.2.1 and prior.
reason: Option<ClosureReason>,
},
/// A channel splice has been negotiated and the funding transaction is pending
/// confirmation on-chain.
/// A channel splice with local inputs or outputs has been negotiated and the funding
/// transaction is pending confirmation on-chain.
///
/// This event is not emitted when only the counterparty contributes to a splice.
Comment thread
tnull marked this conversation as resolved.
SpliceNegotiated {
/// The `channel_id` of the channel.
channel_id: ChannelId,
Expand All @@ -283,7 +283,9 @@ pub enum Event {
/// The outpoint of the channel's splice funding transaction.
new_funding_txo: OutPoint,
},
/// A channel splice negotiation round has failed.
/// A channel splice negotiation round with local inputs or outputs has failed.
///
/// This event is not emitted when only the counterparty contributes to a splice.
SpliceNegotiationFailed {
/// The `channel_id` of the channel.
channel_id: ChannelId,
Expand Down Expand Up @@ -350,7 +352,7 @@ impl_writeable_tlv_based_enum!(Event,
(8, total_fee_earned_msat, option),
(10, skimmed_fee_msat, option),
(12, claim_from_onchain_tx, required),
(14, outbound_amount_forwarded_msat, option),
(14, outbound_amount_forwarded_msat, (default_value, 0)),
(15, prev_htlcs, (default_value_vec, vec![HTLCLocator {
channel_id: legacy_prev_channel_id.ok_or(lightning::ln::msgs::DecodeError::InvalidValue)?,
user_channel_id: legacy_prev_user_channel_id.map(UserChannelId),
Expand Down Expand Up @@ -1500,7 +1502,7 @@ where
from_prev_str,
next_htlcs.len(),
to_next_str,
outbound_amount_forwarded_msat.unwrap_or(0),
outbound_amount_forwarded_msat,
fee_earned,
);
} else {
Expand All @@ -1511,7 +1513,7 @@ where
from_prev_str,
next_htlcs.len(),
to_next_str,
outbound_amount_forwarded_msat.unwrap_or(0),
outbound_amount_forwarded_msat,
fee_earned,
);
}
Expand Down Expand Up @@ -2120,6 +2122,14 @@ mod tests {
counterparty_node_id: Option<PublicKey>,
reason: Option<ClosureReason>,
},
PaymentForwarded {
prev_htlcs: Vec<HTLCLocator>,
next_htlcs: Vec<HTLCLocator>,
total_fee_earned_msat: Option<u64>,
skimmed_fee_msat: Option<u64>,
claim_from_onchain_tx: bool,
outbound_amount_forwarded_msat: Option<u64>,
},
}

impl_writeable_tlv_based_enum!(LegacyEvent,
Expand All @@ -2129,6 +2139,14 @@ mod tests {
(2, user_channel_id, required),
(3, reason, upgradable_option),
},
(7, PaymentForwarded) => {
(8, total_fee_earned_msat, option),
(10, skimmed_fee_msat, option),
(12, claim_from_onchain_tx, required),
(14, outbound_amount_forwarded_msat, option),
(15, prev_htlcs, (default_value_vec, Vec::new())),
(17, next_htlcs, (default_value_vec, Vec::new())),
},
);

fn encode_legacy_event_queue(event: LegacyEvent) -> Vec<u8> {
Expand Down Expand Up @@ -2190,6 +2208,47 @@ mod tests {
assert!(res.is_err());
}

#[test]
fn event_queue_defaults_legacy_missing_forwarded_amount() {
let store: Arc<DynStore> = Arc::new(DynStoreWrapper(InMemoryStore::new()));
let logger = Arc::new(TestLogger::new());
let prev_htlcs = vec![HTLCLocator {
channel_id: ChannelId([1; 32]),
user_channel_id: None,
node_id: None,
}];
let next_htlcs = vec![HTLCLocator {
channel_id: ChannelId([2; 32]),
user_channel_id: None,
node_id: None,
}];
let legacy_event = LegacyEvent::PaymentForwarded {
prev_htlcs: prev_htlcs.clone(),
next_htlcs: next_htlcs.clone(),
total_fee_earned_msat: None,
skimmed_fee_msat: None,
claim_from_onchain_tx: true,
outbound_amount_forwarded_msat: None,
};
let expected_event = LegacyEvent::PaymentForwarded {
prev_htlcs,
next_htlcs,
total_fee_earned_msat: None,
skimmed_fee_msat: None,
claim_from_onchain_tx: true,
outbound_amount_forwarded_msat: Some(0),
};
let persisted_bytes = encode_legacy_event_queue(legacy_event);

let event_queue =
EventQueue::read(&mut &persisted_bytes[..], (Arc::clone(&store), logger)).unwrap();
assert_eq!(
event_queue.next_event().unwrap().encode(),
expected_event.encode(),
"legacy forwarded amount should normalize to zero"
);
}

#[tokio::test]
async fn event_queue_concurrency() {
let store: Arc<DynStore> = Arc::new(DynStoreWrapper(InMemoryStore::new()));
Expand Down
3 changes: 0 additions & 3 deletions tests/common/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1063,7 +1063,6 @@ pub async fn splice_in_with_all(
node_a.splice_in_with_all(user_channel_id, node_b.node_id()).unwrap();

let splice_txo = expect_splice_negotiated_event!(node_a, node_b.node_id());
expect_splice_negotiated_event!(node_b, node_a.node_id());
wait_for_tx(&electrsd.client, splice_txo.txid).await;
}

Expand Down Expand Up @@ -1537,7 +1536,6 @@ pub(crate) async fn do_channel_full_cycle<E: ElectrumApi>(
assert!(splice_out_sat > 500_000);
node_b.splice_out(&user_channel_id_b, node_a.node_id(), &addr_a, splice_out_sat).unwrap();

expect_splice_negotiated_event!(node_a, node_b.node_id());
expect_splice_negotiated_event!(node_b, node_a.node_id());

generate_blocks_and_wait(&bitcoind, electrsd, 6).await;
Expand All @@ -1560,7 +1558,6 @@ pub(crate) async fn do_channel_full_cycle<E: ElectrumApi>(
node_a.splice_in(&user_channel_id_a, node_b.node_id(), splice_in_sat).unwrap();

expect_splice_negotiated_event!(node_a, node_b.node_id());
expect_splice_negotiated_event!(node_b, node_a.node_id());

generate_blocks_and_wait(&bitcoind, electrsd, 6).await;
node_a.sync_wallets().unwrap();
Expand Down
16 changes: 5 additions & 11 deletions tests/integration_tests_rust.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1752,8 +1752,7 @@ async fn splice_channel() {
// Splice-in funds for Node B so that it has outbound liquidity to make a payment
node_b.splice_in(&user_channel_id_b, node_a.node_id(), 4_000_000).unwrap();

let txo = expect_splice_negotiated_event!(node_a, node_b.node_id());
expect_splice_negotiated_event!(node_b, node_a.node_id());
let txo = expect_splice_negotiated_event!(node_b, node_a.node_id());

// Node B contributed to this splice, so wait for its funding broadcast to be classified before
// syncing — otherwise a sync racing the broadcaster's queue records a generic on-chain payment.
Expand Down Expand Up @@ -1813,7 +1812,6 @@ async fn splice_channel() {
node_a.splice_out(&user_channel_id_a, node_b.node_id(), &address, amount_msat / 1000).unwrap();

let txo = expect_splice_negotiated_event!(node_a, node_b.node_id());
expect_splice_negotiated_event!(node_b, node_a.node_id());

// Node A contributed to this splice, so wait for its funding broadcast to be classified before
// syncing — otherwise a sync racing the broadcaster's queue records a generic on-chain payment.
Expand Down Expand Up @@ -1926,8 +1924,7 @@ async fn run_rbf_splice_channel_test(confirm_original: bool) {
// Initiate a splice-in to create a pending splice
node_b.splice_in(&user_channel_id_b, node_a.node_id(), 1_000_000).unwrap();

let original_txo = expect_splice_negotiated_event!(node_a, node_b.node_id());
expect_splice_negotiated_event!(node_b, node_a.node_id());
let original_txo = expect_splice_negotiated_event!(node_b, node_a.node_id());

// Sync so the original splice candidate is recorded as a canonical wallet transaction before
// the RBF below replaces it. The post-RBF sync then observes the original candidate being
Expand Down Expand Up @@ -1964,8 +1961,7 @@ async fn run_rbf_splice_channel_test(confirm_original: bool) {
// bump_channel_funding_fee should succeed when there's a pending splice
node_b.bump_channel_funding_fee(&user_channel_id_b, node_a.node_id()).unwrap();

let rbf_txo = expect_splice_negotiated_event!(node_a, node_b.node_id());
expect_splice_negotiated_event!(node_b, node_a.node_id());
let rbf_txo = expect_splice_negotiated_event!(node_b, node_a.node_id());

assert_ne!(original_txo, rbf_txo, "RBF should produce a different funding txo");

Expand Down Expand Up @@ -2170,8 +2166,7 @@ async fn splice_payment_reorged_to_unconfirmed() {

// node_b splices in, recording a funding payment it contributed to.
node_b.splice_in(&user_channel_id_b, node_a.node_id(), 1_000_000).unwrap();
let splice_txo = expect_splice_negotiated_event!(node_a, node_b.node_id());
expect_splice_negotiated_event!(node_b, node_a.node_id());
let splice_txo = expect_splice_negotiated_event!(node_b, node_a.node_id());
wait_for_tx(&electrsd.client, splice_txo.txid).await;
// Ensure node_b classified the splice before syncing so the test exercises a funding payment's
// reorg rather than a generic on-chain payment's.
Expand Down Expand Up @@ -2248,8 +2243,7 @@ async fn splice_in_rbf_joins_counterparty_splice() {
// node_b (which didn't fund the channel open, so holds the on-chain balance) initiates a
// splice-in; node_a does not contribute to this first candidate.
node_b.splice_in(&user_channel_id_b, node_a.node_id(), 1_000_000).unwrap();
let counterparty_txo = expect_splice_negotiated_event!(node_a, node_b.node_id());
expect_splice_negotiated_event!(node_b, node_a.node_id());
let counterparty_txo = expect_splice_negotiated_event!(node_b, node_a.node_id());
wait_for_tx(&electrsd.client, counterparty_txo.txid).await;
node_a.sync_wallets().unwrap();
node_b.sync_wallets().unwrap();
Expand Down
Loading