Skip to content

Commit

Permalink
Adds Swift code snippets
Browse files Browse the repository at this point in the history
  • Loading branch information
Conor Okus committed Sep 14, 2023
1 parent c1fef0b commit e7febbd
Show file tree
Hide file tree
Showing 6 changed files with 908 additions and 453 deletions.
50 changes: 36 additions & 14 deletions docs/tutorials/building-a-node-with-ldk/connect-to-peers.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
# Connect to Peers

In this section you'll learn how to join the lightning network.
In this section you'll learn how to join the lightning network.

Firstly we need to have the ability to do high performance I/O operations. LDK provides default implementations for initializing all of your networking needs. If you are using Rust, you can use our simple socket handling library `lightning_net_tokio`. In Kotlin/Java you can use the `NioPeerHandler` which uses Java's NIO I/O interface.

**What it's used for**: making peer connections, facilitating peer data to and from LDK

<CodeSwitcher :languages="{rust:'Rust', kotlin:'Kotlin'}">
<template v-slot:rust>
<CodeSwitcher :languages="{rust:'Rust', kotlin:'Kotlin', swift:'Swift'}">
<template v-slot:rust>

```rust
use lightning_net_tokio; // use LDK's sample networking module
Expand Down Expand Up @@ -40,13 +40,23 @@ nioPeerHandler.bind_listener(InetSocketAddress("127.0.0.1", port))
```

</template>
</CodeSwitcher>

<template v-slot:swift>

```Swift
let peerHandler = channelManagerConstructor.getTCPPeerHandler()
let port = 9777
peerHandler.bind(address: "127.0.0.1", port: port)
```

</template>

</CodeSwitcher>

Connections to other peers are established with `PeerManager`. You'll need to know the pubkey and address of another node that you want as a peer. Once the connection is established and the handshake is complete, `PeerManager` will show the peer's pubkey in its list of peers.

<CodeSwitcher :languages="{rust:'Rust', kotlin:'Kotlin'}">
<template v-slot:rust>
<CodeSwitcher :languages="{rust:'Rust', kotlin:'Kotlin', swift:'Swift'}">
<template v-slot:rust>

```rust
match lightning_net_tokio::connect_outbound(Arc::clone(&peer_manager), pubkey, address).await {
Expand Down Expand Up @@ -88,20 +98,32 @@ try {

} catch (e: IOException) {
// Handle failure when connecting to a peer.
}
```

</template>
</CodeSwitcher>

**Dependencies:** `PeerManager`
}

**References:** [Rust `lightning-net-tokio` docs](https://docs.rs/lightning-net-tokio/*/lightning_net_tokio/), [Rust `PeerManager` docs](https://docs.rs/lightning/*/lightning/ln/peer_handler/struct.PeerManager.html), [Java `NioPeerHandler` bindings](https://github.com/lightningdevkit/ldk-garbagecollected/blob/main/src/main/java/org/ldk/batteries/NioPeerHandler.java),
[Java `PeerManager` bindings](https://github.com/lightningdevkit/ldk-garbagecollected/blob/main/src/main/java/org/ldk/structs/PeerManager.java),
````

</template>

<template v-slot:swift>

```Swift
// Connect and wait for the handshake to complete.
let pubKey = // Insert code to retrieve peer's pubKey as byte array
let address = // Insert code to retrieve peer's address
let port = // Insert code to retrieve peer's port
let _ = peerHandler.connect(address: address, port: port, theirNodeId: pubKey)

// The peer's pubkey will be present in the list of peer ids.
let peerManager: PeerManager = channelManagerConstructor.peerManager
let peerNodeIds = peerManager.getPeerNodeIds()
````

</template>

</CodeSwitcher>

**Dependencies:** `PeerManager`

**References:** [Rust `lightning-net-tokio` docs](https://docs.rs/lightning-net-tokio/*/lightning_net_tokio/), [Rust `PeerManager` docs](https://docs.rs/lightning/*/lightning/ln/peer_handler/struct.PeerManager.html), [Java `NioPeerHandler` bindings](https://github.com/lightningdevkit/ldk-garbagecollected/blob/main/src/main/java/org/ldk/batteries/NioPeerHandler.java),
[Java `PeerManager` bindings](https://github.com/lightningdevkit/ldk-garbagecollected/blob/main/src/main/java/org/ldk/structs/PeerManager.java),
73 changes: 48 additions & 25 deletions docs/tutorials/building-a-node-with-ldk/handling-events.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,44 +4,67 @@ LDK requires that you handle many different events throughout your app's life cy

To start handling events in your application, run:

<CodeSwitcher :languages="{rust:'Rust', kotlin:'Kotlin'}">
<CodeSwitcher :languages="{rust:'Rust', kotlin:'Kotlin', swift:'Swift'}">
<template v-slot:rust>

```rust
use lightning::util::events::{Event};

// In the event handler passed to BackgroundProcessor::start
match event {
Event::PaymentSent { payment_preimage } => {
// Handle successful payment
}
Event::PaymentFailed { payment_hash, rejected_by_dest } => {
// Handle failed payment
}
Event::FundingGenerationReady { .. } =>
```rust
use lightning::util::events::{Event};

// In the event handler passed to BackgroundProcessor::start
match event {
Event::PaymentSent { payment_preimage } => {
// Handle successful payment
}
Event::PaymentFailed { payment_hash, rejected_by_dest } => {
// Handle failed payment
}
Event::FundingGenerationReady { .. } =>
}
```
```

</template>

<template v-slot:kotlin>

```java
import org.ldk.structs.Event

if (event is Event.PaymentSent) {
// Handle successful payment
}
if (event is Event.PaymentSent) {
// Handle successful payment
}

if (event is Event.PaymentFailed) {
// Handle failed payment
}
if (event is Event.PaymentFailed) {
// Handle failed payment
}

if (event is Event.FundingGenerationReady) {
// Create a funding tx to be broadcast
}
```
if (event is Event.FundingGenerationReady) {
// Create a funding tx to be broadcast
}

````

</template>

<template v-slot:swift>

```Swift
import LightningDevKit

if let event = event.getValueAsPaymentSent() {
// Handle successful payment
}

if let event = event.getValueAsPaymentFailed() {
// Handle failed payment
}

if let event = event.getValueAsFundingGenerationReady() {
// Create a funding tx to be broadcast
}
````

</template>

</CodeSwitcher>

References: [Rust `Event` docs](https://docs.rs/lightning/0.0.114/lightning/util/events/enum.Event.html), [Java `Event` bindings](https://github.com/lightningdevkit/ldk-garbagecollected/blob/main/src/main/java/org/ldk/structs/Event.java)
References: [Rust `Event` docs](https://docs.rs/lightning/0.0.114/lightning/util/events/enum.Event.html), [Java `Event` bindings](https://github.com/lightningdevkit/ldk-garbagecollected/blob/main/src/main/java/org/ldk/structs/Event.java)
106 changes: 94 additions & 12 deletions docs/tutorials/building-a-node-with-ldk/opening-a-channel.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ Now that you have a peer, you can open a channel with them using `ChannelManager

Channels can be announced to the network or can remain private, which is controlled via `UserConfig::announced_channel`.

<CodeSwitcher :languages="{rust:'Rust', kotlin:'Kotlin'}">
<CodeSwitcher :languages="{rust:'Rust', kotlin:'Kotlin', swift:'Swift'}">
<template v-slot:rust>

```rust
Expand Down Expand Up @@ -51,19 +51,45 @@ val createChannelResult = channelManager.create_channel(
```

</template>

<template v-slot:swift>

```Swift
let amount: UInt64 = 100000
let pushMsat: UInt64 = 1000
let userId: [UInt8] = toBytesArray(UUID().uuid)

// public aka announced channel
let userConfig = UserConfig.initWithDefault()
let channelHandshakeConfig = ChannelHandshakeConfig.initWithDefault()
channelConfig.setAnnouncedChannel(val: true)

userConfig.setChannelHandshakeConfig(val: channelConfig)

let createChannelResults = channelManager.createChannel(
theirNetworkKey: pubKey,
channelValueSatoshis: amount,
pushMsat: pushMsat,
userChannelId: userId,
overrideConfig: userConfig
)
```

</template>

</CodeSwitcher>

# FundingGenerationReady Event Handling

At this point, an outbound channel has been initiated with your peer and it will appear in `ChannelManager::list_channels`. However, the channel is not yet funded. Once your peer accepts the channel, you will be notified with a `FundingGenerationReady` event. It's then your responsibility to construct the funding transaction and pass it to ChannelManager, which will broadcast it once it receives your channel counterparty's signature.
At this point, an outbound channel has been initiated with your peer and it will appear in `ChannelManager::list_channels`. However, the channel is not yet funded. Once your peer accepts the channel, you will be notified with a `FundingGenerationReady` event. It's then your responsibility to construct the funding transaction and pass it to ChannelManager, which will broadcast it once it receives your channel counterparty's signature.

::: tip Note

Remember that the funding transaction must only spend SegWit inputs.

:::

<CodeSwitcher :languages="{rust:'Rust', kotlin:'Kotlin'}">
<CodeSwitcher :languages="{rust:'Rust', kotlin:'Kotlin', swift:'Swift'}">
<template v-slot:rust>

```rust
Expand Down Expand Up @@ -142,14 +168,52 @@ fun buildFundingTx(value: Long, script: ByteArray): Transaction {

</template>

<template v-slot:swift>

```Swift
// After the peer responds with an `accept_channel` message, an
// Event.FundingGenerationReady event will be generated.

if let event = event.getValueAsFundingGenerationReady() {
let script = Script(rawOutputScript: event.getOutputScript())
let channelValue = event.getChannelValueSatoshis()
let rawTx = buildFundingTx(script: script, amount: channelValue)
if let rawTx = rawTx {
channelManager.fundingTransactionGenerated(
temporaryChannelId: event.getTemporaryChannelId(),
counterpartyNodeId: event.getCounterpartyNodeId(),
fundingTransaction: rawTx.serialize()
)
}
}

// Building transaction using BDK
func buildFundingTx(script: Script, amount: UInt64) -> Transaction? {
do {
let transaction = try TxBuilder().addRecipient(
script: script,
amount: amount)
.feeRate(satPerVbyte: 4.0)
.finish(wallet: onchainWallet)
let _ = try onchainWallet.sign(psbt: transaction.psbt, signOptions: nil)
return transaction.psbt.extractTx()
} catch {
return nil
}
}
```

</template>

</CodeSwitcher>

**References:** [Rust `FundingGenerationReady` docs](https://docs.rs/lightning/*/lightning/util/events/enum.Event.html#variant.FundingGenerationReady), [Java `FundingGenerationReady` bindings](https://github.com/lightningdevkit/ldk-garbagecollected/blob/main/src/main/java/org/ldk/structs/Event.java#L95)

# Broadcasting the Funding Transaction

After crafting the funding transaction you'll need to send it to the Bitcoin network where it will hopefully be mined and added to the blockchain. You'll need to watch this transaction and wait for a minimum of 6 confirmations before the channel is ready to use.

<CodeSwitcher :languages="{rust:'Rust', kotlin:'Kotlin'}">
<CodeSwitcher :languages="{rust:'Rust', kotlin:'Kotlin', swift:'Swift'}">
<template v-slot:rust>

```rust
Expand Down Expand Up @@ -197,8 +261,8 @@ object YourTxBroadcaster : BroadcasterInterface.BroadcasterInterfaceInterface {
val transaction = Transaction(uByteArray.toList())

tx?.let {
CoroutineScope(Dispatchers.IO).launch {
blockchain.broadcast(transaction)
CoroutineScope(Dispatchers.IO).launch {
blockchain.broadcast(transaction)
}
} ?: throw(IllegalStateException("Broadcaster attempted to broadcast a null transaction"))

Expand All @@ -208,16 +272,34 @@ object YourTxBroadcaster : BroadcasterInterface.BroadcasterInterfaceInterface {
```

</template>
</CodeSwitcher>

::: tip Keep LDK in sync

Remember if you are restarting and have open channels then you should [let LDK know about the latest channel state.](./setting-up-a-channel-manager/#sync-channelmonitors-and-channelmanager-to-chain-tip)

:::
<template v-slot:swift>

```Swift
// Using BDK (Bitcoin Dev Kit) to broadcast a transaction via the esplora client
class MyBroacaster: BroadcasterInterface {
override func broadcastTransaction(tx: [UInt8]) {
let esploraURL = "esploraUrl"
let esploraConfig = EsploraConfig(baseUrl: esploraURL, proxy: nil, concurrency: 5, stopGap: 20, timeout: nil)
let blockchainConfig = BlockchainConfig.esplora(config: esploraConfig)
let blockchain = Blockchain(config: blockchainConfig)

do {
let transaction = try Transaction(transactionBytes: tx)
try blockchain.broadcast(transaction: transaction)
} catch {
print("Failed to broadcast transaction: \(error.localizedDescription)")
}
}
}
```

</template>

</CodeSwitcher>

::: tip Keep LDK in sync

Remember if you are restarting and have open channels then you should [let LDK know about the latest channel state.](./setting-up-a-channel-manager/#sync-channelmonitors-and-channelmanager-to-chain-tip)

:::
Loading

0 comments on commit e7febbd

Please sign in to comment.