Skip to content
Merged
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
11 changes: 2 additions & 9 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,21 +1,13 @@
# 0.7.0-rc.66 (Synonym Fork)
# 0.7.0-rc.68 (Synonym Fork)

## Bug Fixes

- Prevent native SIGABRT crashes when stopping and rebuilding the node by making runtime teardown deterministic.
- Keep exported payment and liquidity handles from calling into a shutting-down runtime, refuse restart while detached work is still live, and stop Electrum confirm gating from blocking or panicking shutdown.
- Add keep consumer rules for JNA types UniFFI needs under R8.

# 0.7.0-rc.64 (Synonym Fork)

## Bug Fixes

- The Android AAR now ships targeted R8 consumer keep rules for the UniFFI/JNA FFI surface.

# 0.7.0-rc.63 (Synonym Fork)

## Bug Fixes

- Moved peer persistence to async KV storage so slow writes no longer hold the peer-store lock.
- Prevented Electrum runtime self-drop crashes and unbounded shutdown waits.
- Scaled Electrum full-scan timeouts for additional wallets with the configured stop gap and batch
Expand Down Expand Up @@ -84,6 +76,7 @@

## Synonym Fork Additions

- Added explicit accepted, rejected, or unknown broadcast outcomes with transaction IDs for on-chain sends.
- Removed `set_accept_stale_channel_monitors` and the patched Synonym `rust-lightning` branch.
Stale channel-monitor mismatches now fail closed with `BuildError::DangerousValue`.
Lightning crates come from crates.io `0.2.0` again.
Expand Down
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ exclude = ["bindings/uniffi-bindgen"]

[package]
name = "ldk-node"
version = "0.7.0-rc.66"
version = "0.7.0-rc.68"
authors = ["Elias Rohrer <dev@tnull.de>"]
homepage = "https://lightningdevkit.org/"
license = "MIT OR Apache-2.0"
Expand Down
4 changes: 2 additions & 2 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@

import PackageDescription

let tag = "v0.7.0-rc.66"
let checksum = "21ac13bfdc9fdd3099a688bd0053f8b14c74b5957943b2f09624886e65556a8e"
let tag = "v0.7.0-rc.68"
let checksum = "1955a179fdb6acc5159ead68225dd27029d2f2a74c4b8b13164038eb9f95462f"
let url = "https://github.com/synonymdev/ldk-node/releases/download/\(tag)/LDKNodeFFI.xcframework.zip"

let package = Package(
Expand Down
17 changes: 17 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,23 @@ LDK Node currently comes with a decidedly opinionated set of design choices:
- Gossip data may be sourced via Lightning's peer-to-peer network or the [Rapid Gossip Sync](https://docs.rs/lightning-rapid-gossip-sync/*/lightning_rapid_gossip_sync/) protocol.
- Entropy for the Lightning and on-chain wallets may be sourced from raw bytes or a [BIP39](https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki) mnemonic. In addition, LDK Node offers the means to generate and persist the entropy bytes to disk.

### On-chain send results

`OnchainPayment::send_to_address_with_broadcast_result` and
`send_all_to_address_with_broadcast_result` submit a signed transaction directly to the
configured chain source. They return `Accepted { txid }` only when that backend acknowledges
the submitted transaction. `Rejected { txid, reason }` records a recognized refusal response;
`Unknown { txid }` covers a lost or ambiguous result. Both retain the locally computed txid.
Neither a refusal nor an unknown result proves the transaction was never delivered, so callers
must not create a replacement payment from either result. Backend acknowledgement is not
confirmation or guaranteed network propagation. An `Err` from these methods means this call did
not initiate broadcast.

The existing `send_to_address` and `send_all_to_address` methods still return a local txid after
attempting queue admission, even if admission fails. Their returned txid gives no backend
acceptance assurance. The on-chain variant of
`UnifiedQrPayment::send` has the same queueing semantics.

## Language Support
LDK Node itself is written in [Rust][rust] and may therefore be natively added as a library dependency to any `std` Rust program. However, beyond its Rust API it also offers language bindings for [Swift][swift], [Kotlin][kotlin], and [Python][python] based on the [UniFFI](https://github.com/mozilla/uniffi-rs/). Moreover, [Flutter bindings][flutter_bindings] are also available.

Expand Down
2 changes: 1 addition & 1 deletion bindings/kotlin/ldk-node-android/gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ android.useAndroidX=true
android.enableJetifier=true
kotlin.code.style=official
group=com.synonym
version=0.7.0-rc.66
version=0.7.0-rc.68
Original file line number Diff line number Diff line change
Expand Up @@ -1549,6 +1549,10 @@ internal typealias UniffiVTableCallbackInterfaceVssHeaderProviderUniffiByValue =










Expand Down Expand Up @@ -2738,6 +2742,13 @@ internal interface UniffiLib : Library {
`feeRate`: RustBufferByValue,
uniffiCallStatus: UniffiRustCallStatus,
): RustBufferByValue
fun uniffi_ldk_node_fn_method_onchainpayment_send_all_to_address_with_broadcast_result(
`ptr`: Pointer?,
`address`: RustBufferByValue,
`retainReserves`: Byte,
`feeRate`: RustBufferByValue,
uniffiCallStatus: UniffiRustCallStatus,
): RustBufferByValue
fun uniffi_ldk_node_fn_method_onchainpayment_send_to_address(
`ptr`: Pointer?,
`address`: RustBufferByValue,
Expand All @@ -2746,6 +2757,14 @@ internal interface UniffiLib : Library {
`utxosToSpend`: RustBufferByValue,
uniffiCallStatus: UniffiRustCallStatus,
): RustBufferByValue
fun uniffi_ldk_node_fn_method_onchainpayment_send_to_address_with_broadcast_result(
`ptr`: Pointer?,
`address`: RustBufferByValue,
`amountSats`: Long,
`feeRate`: RustBufferByValue,
`utxosToSpend`: RustBufferByValue,
uniffiCallStatus: UniffiRustCallStatus,
): RustBufferByValue
fun uniffi_ldk_node_fn_clone_refund(
`ptr`: Pointer?,
uniffiCallStatus: UniffiRustCallStatus,
Expand Down Expand Up @@ -3506,8 +3525,12 @@ internal interface UniffiLib : Library {
): Short
fun uniffi_ldk_node_checksum_method_onchainpayment_send_all_to_address(
): Short
fun uniffi_ldk_node_checksum_method_onchainpayment_send_all_to_address_with_broadcast_result(
): Short
fun uniffi_ldk_node_checksum_method_onchainpayment_send_to_address(
): Short
fun uniffi_ldk_node_checksum_method_onchainpayment_send_to_address_with_broadcast_result(
): Short
fun uniffi_ldk_node_checksum_method_refund_absolute_expiry_seconds(
): Short
fun uniffi_ldk_node_checksum_method_refund_amount_msats(
Expand Down Expand Up @@ -4153,9 +4176,15 @@ private fun uniffiCheckApiChecksums(lib: UniffiLib) {
if (lib.uniffi_ldk_node_checksum_method_onchainpayment_send_all_to_address() != 37748.toShort()) {
throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project")
}
if (lib.uniffi_ldk_node_checksum_method_onchainpayment_send_all_to_address_with_broadcast_result() != 45110.toShort()) {
throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project")
}
if (lib.uniffi_ldk_node_checksum_method_onchainpayment_send_to_address() != 28826.toShort()) {
throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project")
}
if (lib.uniffi_ldk_node_checksum_method_onchainpayment_send_to_address_with_broadcast_result() != 16277.toShort()) {
throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project")
}
if (lib.uniffi_ldk_node_checksum_method_refund_absolute_expiry_seconds() != 43722.toShort()) {
throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project")
}
Expand Down Expand Up @@ -8625,6 +8654,21 @@ open class OnchainPayment: Disposable, OnchainPaymentInterface {
})
}

@Throws(NodeException::class)
override fun `sendAllToAddressWithBroadcastResult`(`address`: Address, `retainReserves`: kotlin.Boolean, `feeRate`: FeeRate?): OnchainSendResult {
return FfiConverterTypeOnchainSendResult.lift(callWithPointer {
uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus ->
UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_onchainpayment_send_all_to_address_with_broadcast_result(
it,
FfiConverterTypeAddress.lower(`address`),
FfiConverterBoolean.lower(`retainReserves`),
FfiConverterOptionalTypeFeeRate.lower(`feeRate`),
uniffiRustCallStatus,
)
}
})
}

@Throws(NodeException::class)
override fun `sendToAddress`(`address`: Address, `amountSats`: kotlin.ULong, `feeRate`: FeeRate?, `utxosToSpend`: List<SpendableUtxo>?): Txid {
return FfiConverterTypeTxid.lift(callWithPointer {
Expand All @@ -8641,6 +8685,22 @@ open class OnchainPayment: Disposable, OnchainPaymentInterface {
})
}

@Throws(NodeException::class)
override fun `sendToAddressWithBroadcastResult`(`address`: Address, `amountSats`: kotlin.ULong, `feeRate`: FeeRate?, `utxosToSpend`: List<SpendableUtxo>?): OnchainSendResult {
return FfiConverterTypeOnchainSendResult.lift(callWithPointer {
uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus ->
UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_onchainpayment_send_to_address_with_broadcast_result(
it,
FfiConverterTypeAddress.lower(`address`),
FfiConverterULong.lower(`amountSats`),
FfiConverterOptionalTypeFeeRate.lower(`feeRate`),
FfiConverterOptionalSequenceTypeSpendableUtxo.lower(`utxosToSpend`),
uniffiRustCallStatus,
)
}
})
}




Expand Down Expand Up @@ -12543,6 +12603,74 @@ object FfiConverterTypeOfferAmount : FfiConverterRustBuffer<OfferAmount>{



object FfiConverterTypeOnchainSendResult : FfiConverterRustBuffer<OnchainSendResult>{
override fun read(buf: ByteBuffer): OnchainSendResult {
return when(buf.getInt()) {
1 -> OnchainSendResult.Accepted(
FfiConverterTypeTxid.read(buf),
)
2 -> OnchainSendResult.Rejected(
FfiConverterTypeTxid.read(buf),
FfiConverterString.read(buf),
)
3 -> OnchainSendResult.Unknown(
FfiConverterTypeTxid.read(buf),
)
else -> throw RuntimeException("invalid enum value, something is very wrong!!")
}
}

override fun allocationSize(value: OnchainSendResult) = when(value) {
is OnchainSendResult.Accepted -> {
// Add the size for the Int that specifies the variant plus the size needed for all fields
(
4UL
+ FfiConverterTypeTxid.allocationSize(value.`txid`)
)
}
is OnchainSendResult.Rejected -> {
// Add the size for the Int that specifies the variant plus the size needed for all fields
(
4UL
+ FfiConverterTypeTxid.allocationSize(value.`txid`)
+ FfiConverterString.allocationSize(value.`reason`)
)
}
is OnchainSendResult.Unknown -> {
// Add the size for the Int that specifies the variant plus the size needed for all fields
(
4UL
+ FfiConverterTypeTxid.allocationSize(value.`txid`)
)
}
}

override fun write(value: OnchainSendResult, buf: ByteBuffer) {
when(value) {
is OnchainSendResult.Accepted -> {
buf.putInt(1)
FfiConverterTypeTxid.write(value.`txid`, buf)
Unit
}
is OnchainSendResult.Rejected -> {
buf.putInt(2)
FfiConverterTypeTxid.write(value.`txid`, buf)
FfiConverterString.write(value.`reason`, buf)
Unit
}
is OnchainSendResult.Unknown -> {
buf.putInt(3)
FfiConverterTypeTxid.write(value.`txid`, buf)
Unit
}
}.let { /* this makes the `when` an expression, which ensures it is exhaustive */ }
}
}





object FfiConverterTypePaymentDirection: FfiConverterRustBuffer<PaymentDirection> {
override fun read(buf: ByteBuffer) = try {
PaymentDirection.entries[buf.getInt() - 1]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -653,9 +653,15 @@ interface OnchainPaymentInterface {
@Throws(NodeException::class)
fun `sendAllToAddress`(`address`: Address, `retainReserve`: kotlin.Boolean, `feeRate`: FeeRate?): Txid

@Throws(NodeException::class)
fun `sendAllToAddressWithBroadcastResult`(`address`: Address, `retainReserves`: kotlin.Boolean, `feeRate`: FeeRate?): OnchainSendResult

@Throws(NodeException::class)
fun `sendToAddress`(`address`: Address, `amountSats`: kotlin.ULong, `feeRate`: FeeRate?, `utxosToSpend`: List<SpendableUtxo>?): Txid

@Throws(NodeException::class)
fun `sendToAddressWithBroadcastResult`(`address`: Address, `amountSats`: kotlin.ULong, `feeRate`: FeeRate?, `utxosToSpend`: List<SpendableUtxo>?): OnchainSendResult

companion object
}

Expand Down Expand Up @@ -2051,6 +2057,32 @@ sealed class OfferAmount {



@kotlinx.serialization.Serializable
sealed class OnchainSendResult {
@kotlinx.serialization.Serializable
data class Accepted(
val `txid`: Txid,
) : OnchainSendResult() {
}
@kotlinx.serialization.Serializable
data class Rejected(
val `txid`: Txid,
val `reason`: kotlin.String,
) : OnchainSendResult() {
}
@kotlinx.serialization.Serializable
data class Unknown(
val `txid`: Txid,
) : OnchainSendResult() {
}

}







@kotlinx.serialization.Serializable
enum class PaymentDirection {
Expand Down
2 changes: 1 addition & 1 deletion bindings/kotlin/ldk-node-jvm/gradle.properties
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
org.gradle.jvmargs=-Xmx1536m
kotlin.code.style=official
group=com.synonym
version=0.7.0-rc.66
version=0.7.0-rc.68
11 changes: 11 additions & 0 deletions bindings/ldk_node.udl
Original file line number Diff line number Diff line change
Expand Up @@ -387,6 +387,10 @@ interface OnchainPayment {
[Throws=NodeError]
Txid send_all_to_address([ByRef]Address address, boolean retain_reserve, FeeRate? fee_rate);
[Throws=NodeError]
OnchainSendResult send_to_address_with_broadcast_result([ByRef]Address address, u64 amount_sats, FeeRate? fee_rate, sequence<SpendableUtxo>? utxos_to_spend);
[Throws=NodeError]
OnchainSendResult send_all_to_address_with_broadcast_result([ByRef]Address address, boolean retain_reserves, FeeRate? fee_rate);
[Throws=NodeError]
Txid bump_fee_by_rbf([ByRef]Txid txid, FeeRate fee_rate);
[Throws=NodeError]
Txid accelerate_by_cpfp([ByRef]Txid txid, FeeRate? fee_rate, Address? destination_address);
Expand All @@ -398,6 +402,13 @@ interface OnchainPayment {
u64 calculate_send_all_fee([ByRef]Address address, boolean retain_reserves, FeeRate? fee_rate);
};

[Enum]
interface OnchainSendResult {
Accepted(Txid txid);
Rejected(Txid txid, string reason);
Unknown(Txid txid);
};

enum CoinSelectionAlgorithm {
"BranchAndBound",
"LargestFirst",
Expand Down
2 changes: 1 addition & 1 deletion bindings/python/pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "ldk_node"
version = "0.7.0-rc.66"
version = "0.7.0-rc.68"
authors = [
{ name="Elias Rohrer", email="dev@tnull.de" },
]
Expand Down
Loading
Loading