Skip to content

Commit

Permalink
Merge pull request #114 from tnull/2023-05-get-bindings-release-ready
Browse files Browse the repository at this point in the history
Get binding generation & publishing ready for 0.1 release
  • Loading branch information
tnull committed Jun 21, 2023
2 parents 59a425e + 7de04b7 commit 68a5086
Show file tree
Hide file tree
Showing 29 changed files with 316 additions and 184 deletions.
19 changes: 18 additions & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,17 @@ jobs:
build:
strategy:
matrix:
toolchain: [ stable, beta ]
toolchain: [
stable,
beta,
1.60.0, # Our MSRV
]
include:
- toolchain: stable
check-fmt: true
build-uniffi: true
- toolchain: 1.60.0
msrv: true
runs-on: ubuntu-latest
steps:
- name: Checkout source code
Expand All @@ -20,17 +27,27 @@ jobs:
toolchain: ${{ matrix.toolchain }}
override: true
profile: minimal
- name: Pin packages to allow for MSRV
if: matrix.msrv
run: cargo update -p hashlink --precise "0.8.1" --verbose # hashlink 0.8.2 requires hashbrown 0.13, requiring 1.61.0
- name: Build on Rust ${{ matrix.toolchain }}
run: cargo build --verbose --color always
- name: Build with UniFFI support on Rust ${{ matrix.toolchain }}
if: matrix.build-uniffi
run: cargo build --features uniffi --verbose --color always
- name: Build documentation on Rust ${{ matrix.toolchain }}
run: |
cargo doc --release --verbose --color always
cargo doc --document-private-items --verbose --color always
- name: Check release build on Rust ${{ matrix.toolchain }}
run: cargo check --release --verbose --color always
- name: Check release build with UniFFI support on Rust ${{ matrix.toolchain }}
if: matrix.build-uniffi
run: cargo check --release --features uniffi --verbose --color always
- name: Test on Rust ${{ matrix.toolchain }}
run: cargo test
- name: Test with UniFFI support on Rust ${{ matrix.toolchain }}
if: matrix.build-uniffi
run: cargo test --features uniffi
- name: Check formatting on Rust ${{ matrix.toolchain }}
if: matrix.check-fmt
Expand Down
35 changes: 35 additions & 0 deletions Package.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// swift-tools-version:5.5
// The swift-tools-version declares the minimum version of Swift required to build this package.

import PackageDescription

let tag = "0.1-alpha.1"
let checksum = "d91403566498f01cdaaafc07a9360ef661151e64075c6d83bbce4c9b5bfa7cee"
let url = "https://github.com/lightningdevkit/ldk-node/releases/download/\(tag)/LDKNodeFFI.xcframework.zip"

let package = Package(
name: "ldk-node",
platforms: [
.iOS(.v15),
.macOS(.v12),
],
products: [
// Products define the executables and libraries a package produces, and make them visible to other packages.
.library(
name: "LDKNode",
targets: ["LDKNodeFFI", "LDKNode"]),
],
targets: [
.target(
name: "LDKNode",
dependencies: ["LDKNodeFFI"],
path: "./bindings/swift/Sources",
swiftSettings: [.unsafeFlags(["-suppress-warnings"])]
),
.binaryTarget(
name: "LDKNodeFFI",
url: url,
checksum: checksum
)
]
)
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ fn main() {

node.start().unwrap();

let funding_address = node.new_funding_address();
let funding_address = node.new_onchain_address();

// .. fund address ..

Expand Down Expand Up @@ -59,6 +59,9 @@ LDK Node currently comes with a decidedly opinionated set of design choices:
## 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.

## MSRV
The Minimum Supported Rust Version (MSRV) is currently 1.60.0.

[api_docs]: https://docs.rs/ldk-node/*/ldk_node/
[api_docs_node]: https://docs.rs/ldk-node/*/ldk_node/struct.Node.html
[api_docs_builder]: https://docs.rs/ldk-node/*/ldk_node/struct.Builder.html
Expand Down
29 changes: 2 additions & 27 deletions bindings/kotlin/ldk-node-android/lib/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ afterEvaluate {
pom {
name.set("ldk-node-android")
description.set(
"LDK Node, a ready-to-go node implementation built using LDK."
"LDK Node, a ready-to-go Lightning node library built using LDK and BDK."
)
url.set("https://lightningdevkit.org")
licenses {
Expand All @@ -85,12 +85,7 @@ afterEvaluate {
developer {
id.set("tnull")
name.set("Elias Rohrer")
email.set("[email protected]")
}
developer {
id.set("jurvis")
name.set("Jurvis Tan")
email.set("[email protected]")
email.set("[email protected]")
}
}
scm {
Expand All @@ -111,23 +106,3 @@ signing {
useInMemoryPgpKeys(signingKeyId, signingKey, signingPassword)
sign(publishing.publications)
}

//tasks.named<Test>("test") {
// // Use JUnit Platform for unit tests.
// useJUnitPlatform()
//
// testLogging {
// events(PASSED, SKIPPED, FAILED, STANDARD_OUT, STANDARD_ERROR)
// exceptionFormat = FULL
// showExceptions = true
// showCauses = true
// showStackTraces = true
// showStandardStreams = true
// }
//}

//// This task dependency ensures that we build the bindings
//// binaries before running the tests
//tasks.withType<KotlinCompile> {
// dependsOn("buildAndroidLib")
//}
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
@RunWith(AndroidJUnit4::class)
class AndroidLibTest {
@Test fun node_start_stop() {
val network: Network = "regtest"
assertEquals(network, "regtest")
val network = Network.REGTEST

val tmpDir1 = createTempDirectory("ldk_node").toString()
println("Random dir 1: $tmpDir1")
Expand All @@ -27,8 +26,8 @@ class AndroidLibTest {
val listenAddress1 = "127.0.0.1:2323"
val listenAddress2 = "127.0.0.1:2324"

val config1 = Config(tmpDir1, "http://127.0.0.1:3002", network, listenAddress1, 2048u)
val config2 = Config(tmpDir2, "http://127.0.0.1:3002", network, listenAddress2, 2048u)
val config1 = Config(tmpDir1, network, listenAddress1, 2048u)
val config2 = Config(tmpDir2, network, listenAddress2, 2048u)

val builder1 = Builder.fromConfig(config1)
val builder2 = Builder.fromConfig(config2)
Expand All @@ -45,10 +44,10 @@ class AndroidLibTest {
val nodeId2 = node2.nodeId()
println("Node Id 2: $nodeId2")

val address1 = node1.newFundingAddress()
val address1 = node1.newOnchainAddress()
println("Funding address 1: $address1")

val address2 = node2.newFundingAddress()
val address2 = node2.newOnchainAddress()
println("Funding address 2: $address2")

node1.stop()
Expand Down
17 changes: 7 additions & 10 deletions bindings/kotlin/ldk-node-jvm/lib/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ afterEvaluate {
pom {
name.set("ldk-node-jvm")
description.set(
"LDK Node, a ready-to-go node implementation built using LDK."
"LDK Node, a ready-to-go Lightning node library built using LDK and BDK."
)
url.set("https://lightningdevkit.org")
licenses {
Expand All @@ -80,15 +80,12 @@ afterEvaluate {
}
}
developers {
developer {
id.set("tnull")
name.set("Elias Rohrer")
email.set("[email protected]")
}
developer {
id.set("jurvis")
name.set("Jurvis Tan")
email.set("[email protected]")
developers {
developer {
id.set("tnull")
name.set("Elias Rohrer")
email.set("[email protected]")
}
}
}
scm {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,19 @@ fun runCommandAndWait(cmd: String): String {
return stdout + stderr
}

fun mine(blocks: UInt) {
fun mine(blocks: UInt): String {
val address = runCommandAndWait("bitcoin-cli -regtest getnewaddress")
val output = runCommandAndWait("bitcoin-cli -regtest generatetoaddress $blocks $address")
println("Mining output: $output")
val re = Regex("\n.+\n\\]$")
val lastBlock = re.find(output)!!.value.replace("]","").replace("\"", "").replace("\n","").trim()
println("Last block: $lastBlock")
return lastBlock
}

fun mineAndWait(esploraEndpoint: String, blocks: UInt) {
val lastBlockHash = mine(blocks)
waitForBlock(esploraEndpoint, lastBlockHash)
}

fun sendToAddress(address: String, amountSats: UInt): String {
Expand All @@ -39,6 +48,7 @@ fun setup() {
runCommandAndWait("bitcoin-cli -regtest createwallet ldk_node_test")
runCommandAndWait("bitcoin-cli -regtest loadwallet ldk_node_test true")
mine(101u)
Thread.sleep(5_000)
}

fun waitForTx(esploraEndpoint: String, txid: String) {
Expand All @@ -53,16 +63,32 @@ fun waitForTx(esploraEndpoint: String, txid: String) {
val response = client.send(request, HttpResponse.BodyHandlers.ofString());

esploraPickedUpTx = re.containsMatchIn(response.body());
Thread.sleep(1_000)
Thread.sleep(500)
}
}

fun waitForBlock(esploraEndpoint: String, blockHash: String) {
var esploraPickedUpBlock = false
val re = Regex("\"in_best_chain\":true");
while (!esploraPickedUpBlock) {
val client = HttpClient.newBuilder().build()
val request = HttpRequest.newBuilder()
.uri(URI.create(esploraEndpoint + "/block/" + blockHash + "/status"))
.build();

val response = client.send(request, HttpResponse.BodyHandlers.ofString());
val body = response.body()

esploraPickedUpBlock = re.containsMatchIn(response.body());
Thread.sleep(500)
}
}

class LibraryTest {
@Test fun fullCycle() {
val esploraEndpoint = "http://127.0.0.1:3002"
setup()

val network = Network.REGTEST

val tmpDir1 = createTempDirectory("ldk_node").toString()
println("Random dir 1: $tmpDir1")
val tmpDir2 = createTempDirectory("ldk_node").toString()
Expand All @@ -71,13 +97,27 @@ class LibraryTest {
val listenAddress1 = "127.0.0.1:2323"
val listenAddress2 = "127.0.0.1:2324"

val esploraEndpoint = "http://127.0.0.1:3002"
val logLevel = LogLevel.TRACE;

val config1 = Config()
config1.storageDirPath = tmpDir1
config1.listeningAddress = listenAddress1
config1.network = Network.REGTEST
config1.logLevel = LogLevel.TRACE

val config1 = Config(tmpDir1, esploraEndpoint, network, listenAddress1, 2048u)
val config2 = Config(tmpDir2, esploraEndpoint, network, listenAddress2, 2048u)
println("Config 1: $config1")

val config2 = Config()
config2.storageDirPath = tmpDir2
config2.listeningAddress = listenAddress2
config2.network = Network.REGTEST
config2.logLevel = LogLevel.TRACE
println("Config 2: $config2")

val builder1 = Builder.fromConfig(config1)
builder1.setEsploraServer(esploraEndpoint)
val builder2 = Builder.fromConfig(config2)
builder2.setEsploraServer(esploraEndpoint)

val node1 = builder1.build()
val node2 = builder2.build()
Expand All @@ -91,15 +131,15 @@ class LibraryTest {
val nodeId2 = node2.nodeId()
println("Node Id 2: $nodeId2")

val address1 = node1.newFundingAddress()
val address1 = node1.newOnchainAddress()
println("Funding address 1: $address1")

val address2 = node2.newFundingAddress()
val address2 = node2.newOnchainAddress()
println("Funding address 2: $address2")

val txid1 = sendToAddress(address1, 100000u)
val txid2 = sendToAddress(address2, 100000u)
mine(6u)
mineAndWait(esploraEndpoint, 6u)

waitForTx(esploraEndpoint, txid1)
waitForTx(esploraEndpoint, txid2)
Expand Down Expand Up @@ -139,7 +179,7 @@ class LibraryTest {

waitForTx(esploraEndpoint, fundingTxid)

mine(6u)
mineAndWait(esploraEndpoint, 6u)

node1.syncWallets()
node2.syncWallets()
Expand Down Expand Up @@ -196,10 +236,7 @@ class LibraryTest {
assert(channelClosedEvent2 is Event.ChannelClosed)
node2.eventHandled()

mine(1u)

// Sleep a bit to allow for the block to propagate to esplora
Thread.sleep(5_000)
mineAndWait(esploraEndpoint, 1u)

node1.syncWallets()
node2.syncWallets()
Expand Down
2 changes: 1 addition & 1 deletion bindings/ldk_node.udl
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ interface LDKNode {
PublicKey node_id();
NetAddress? listening_address();
[Throws=NodeError]
Address new_funding_address();
Address new_onchain_address();
[Throws=NodeError]
Txid send_to_onchain_address([ByRef]Address address, u64 amount_msat);
[Throws=NodeError]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<key>LibraryIdentifier</key>
<string>macos-arm64_x86_64</string>
<key>LibraryPath</key>
<string>ldk_nodeFFI.framework</string>
<string>LDKNodeFFI.framework</string>
<key>SupportedArchitectures</key>
<array>
<string>arm64</string>
Expand All @@ -21,7 +21,7 @@
<key>LibraryIdentifier</key>
<string>ios-arm64_x86_64-simulator</string>
<key>LibraryPath</key>
<string>ldk_nodeFFI.framework</string>
<string>LDKNodeFFI.framework</string>
<key>SupportedArchitectures</key>
<array>
<string>arm64</string>
Expand All @@ -36,7 +36,7 @@
<key>LibraryIdentifier</key>
<string>ios-arm64</string>
<key>LibraryPath</key>
<string>ldk_nodeFFI.framework</string>
<string>LDKNodeFFI.framework</string>
<key>SupportedArchitectures</key>
<array>
<string>arm64</string>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// This is the "umbrella header" for our combined Rust code library.
// It needs to import all of the individual headers.

#import "ldk_nodeFFI.h"
#import "LDKNodeFFI.h"
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
framework module LDKNodeFFI {
umbrella header "LDKNodeFFI-umbrella.h"

export *
module * { export * }
}
Loading

0 comments on commit 68a5086

Please sign in to comment.