Skip to content

Commit 485f4ee

Browse files
committed
Slightly expand documentation and fix ChannelManager dependency within the PeerManager.
1 parent e3c6da0 commit 485f4ee

12 files changed

+1964
-1370
lines changed

Documentation/ChannelManager.md

+26-4
Original file line numberDiff line numberDiff line change
@@ -39,14 +39,36 @@ let feeEstimator = LDKFeeEstimator(
3939

4040
### ManyChannelMonitor ([Rust](https://docs.rs/lightning/0.0.11/lightning/ln/channelmonitor/trait.ManyChannelMonitor.html))
4141

42-
The channel monitor is responsible for registering monitors for relevant on-chain events. For the
43-
sake of simplicity, however, we will initially rely on a placeholder instantiation using
42+
The channel monitor is responsible for registering monitors for relevant on-chain events. For now,
43+
in the interest of simplicity, we will simply stub out all the methods it supports without
44+
putting in actual processing. The following snippet of Swift could should give you an idea
45+
of what such a stub would look like:
4446

4547
```swift
46-
let channelMonitor = LDKManyChannelMonitor()
48+
func addMonitor(this_arg: UnsafeRawPointer?, funding_txo: LDKOutPoint, monitor: LDKChannelMonitor) -> LDKCResult_NoneChannelMonitorUpdateErrZ {
49+
print("adding monitor")
50+
return LDKCResult_NoneChannelMonitorUpdateErrZ()
51+
}
52+
53+
func updateMonitor(this_arg: UnsafeRawPointer?, funding_txo: LDKOutPoint, update: LDKChannelMonitorUpdate) -> LDKCResult_NoneChannelMonitorUpdateErrZ {
54+
print("updating monitor")
55+
return LDKCResult_NoneChannelMonitorUpdateErrZ()
56+
}
57+
58+
func clearPendingHTLCs(this_arg: UnsafeRawPointer?) -> LDKCVec_HTLCUpdateZ {
59+
print("clearing pending HTLCs")
60+
return LDKCVec_HTLCUpdateZ()
61+
}
62+
63+
let manyChannelMonitor = LDKManyChannelMonitor(
64+
this_arg: instance,
65+
add_monitor: addMonitor,
66+
update_monitor: updateMonitor,
67+
get_and_clear_pending_htlcs_updated: clearPendingHTLCs
68+
)
4769
```
4870

49-
This will, however, be a **critical** component to update later on.
71+
The above example is, as of yet, stubbed out, but it will be a **critical** component to update later on.
5072

5173
### Broadcaster Interface ([Rust](https://docs.rs/lightning/0.0.11/lightning/chain/chaininterface/trait.BroadcasterInterface.html))
5274

Documentation/Coordination.md

+14-2
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,22 @@ message handler, is responsible for peer-to-peer-communication. Even though it h
2323
involved prerequisites, it is the first Rust Lightning component most developers integrating
2424
the bindings will interact and experiment with.
2525

26+
## Reference
27+
28+
Should you feel the need for further, in-depth guidance, you might find a referential C++
29+
demo implementation to be very useful. As pointed out [earlier](GettingStarted.md#header-files),
30+
the demo file located in `lightning-c-bindings/demo.cpp` should be a very focused,
31+
distilled no-nonsense example of getting the bindings working with the bare minimum of
32+
external dependencies.
33+
2634
## Next
2735

2836
There are still aspects of the bindings this guide doesn't touch on yet, such as the proper
2937
instantiation of a [ManyChannelMonitor](https://docs.rs/lightning/0.0.11/lightning/ln/channelmonitor/trait.ManyChannelMonitor.html),
30-
custom key management and external signing, as well as user-triggered channel state updates.
38+
custom key management and external signing.
39+
40+
We would like to touch on some user-triggered actions, such as showing a payment invoice
41+
or calculating a payment route (likely based on the input of such an invoice), in this next
42+
section about [User Actions](UserActions.md).
3143

32-
We hope to add those very soon!
44+
As to the other missing parts, we hope to add those very soon!

Documentation/GettingStarted.md

+12-4
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,18 @@ either C or C++ header files. The header files don't vary between architectures,
1919
convenience, they are already provided in the `include` subdirectory. (The full path from
2020
the project root is thus `lightning-c-bindings/include`.)
2121

22-
As we're primarily focused on the application in Swift, we cannot use C++ header files, so the
23-
only two files from that directory we need are `lightning.h` and `rust_types.h`.
24-
25-
If you're working with C++, you will instead only need `lightning.hpp`.
22+
As we're primarily focused on the application in Swift, we cannot use C++ header files due to
23+
the environment constraints set by Apple, so the only two files from that directory that
24+
we will need are `lightning.h` and `rust_types.h`.
25+
26+
Nonetheless, we do strongly encourage working with the C++ bindings if your environment supports
27+
it, given the plethora of "free" benefits that provides, such as memory deallocation, as well
28+
as the convenience of instance methods. If you do end up working with C++,
29+
you will only need `lightning.hpp` for the header reference.
30+
31+
One additional benefit of C++ is the reference demo file, located at
32+
`lightning-c-bindings/demo.cpp`, which should prove a handy guide as you navigate your way
33+
through building support in a new environment.
2634

2735
## Compilation
2836

Documentation/README.md

+7-2
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ This guide aims to give the reader an overview of the structure of Rust Lightnin
44
as well as a reference for integrating the exported bindings in an object-oriented language using
55
Swift as the example.
66

7+
If you are here, we sincerely wish to thank you for working on expanding the Lightning
8+
Development Kit's scope to yet another, new, environment. We hope that this guide makes that
9+
task easier, and removes unnecessary roadblocks.
10+
711
## Architecture
812

913
To run a Lightning node, there are several fundamental components that need setting up.
@@ -37,7 +41,7 @@ implementing the [ChainWatchInterface](https://docs.rs/lightning/0.0.11/lightnin
3741
trait, which would allow Rust Lightning to tell us when new transactions or outpoints become
3842
relevant and should be watched for on-chain.
3943

40-
An alternatively, for the developer slightly more naïve approach, is relying on the
44+
An alternative approach, one that is slightly more naïve from a developer's perspective, is relying on the
4145
[BlockNotifier](https://docs.rs/lightning/0.0.11/lightning/chain/chaininterface/struct.BlockNotifier.html)
4246
struct, which will let us feed raw block data to it and simply keep track of reorgs to deregister
4347
or unconfirm blocks if need be.
@@ -74,4 +78,5 @@ in this document.
7478
* [PeerManager](PeerManager.md)
7579
* [ChannelManager](ChannelManager.md)
7680
* [BlockNotifier](BlockNotifier.md)
77-
* [Coordination](Coordination.md)
81+
* [Coordination](Coordination.md)
82+
* [User Actions](UserActions.md)

Documentation/UserActions.md

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# User Actions
2+
3+
## Invoices
4+
5+
// TODO
6+
7+
### Generate a payment invoice
8+
9+
### Parse a payment invoice
10+
11+
## Route Calculation
12+
13+
// In progress; Arik is experimenting with the freshly exposed code.

Swift Rust FFI.xcodeproj/project.pbxproj

+4
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
2DD11E177CCCC9E9C4D3E949 /* Coordination.md in Sources */ = {isa = PBXBuildFile; fileRef = 2DD11896B49A9872990F4B75 /* Coordination.md */; };
4444
2DD11E554B923CFD2ACC66B5 /* BlockListener.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2DD1114BCCB63083A0C97DB6 /* BlockListener.swift */; };
4545
2DD11E689A19E6FE3660C28D /* CustomPeer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2DD11A892D5A07AE47006E98 /* CustomPeer.swift */; };
46+
2DD11F50EF7D9C09EF5A869B /* UserActions.md in Sources */ = {isa = PBXBuildFile; fileRef = 2DD112313DB3181E0851EE46 /* UserActions.md */; };
4647
2DD11FD9D863B2994D8DF3CB /* ChannelManager.md in Sources */ = {isa = PBXBuildFile; fileRef = 2DD11A364D265C16AF639C21 /* ChannelManager.md */; };
4748
9CC87346C07A1FC6013EC06F /* Pods_Swift_Rust_FFI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 769F94D0AF02F1B815B4006B /* Pods_Swift_Rust_FFI.framework */; };
4849
EC130784C3A8F72C6D855FA3 /* Pods_Swift_Rust_FFI_Swift_Rust_FFITests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 691A071346B646857399E1A1 /* Pods_Swift_Rust_FFI_Swift_Rust_FFITests.framework */; };
@@ -84,6 +85,7 @@
8485
2DD11071A3A772E151D7B6A1 /* BlockNotifier.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = BlockNotifier.md; sourceTree = "<group>"; };
8586
2DD110AA3B0A133662005BE6 /* rust_types.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = rust_types.h; sourceTree = "<group>"; };
8687
2DD1114BCCB63083A0C97DB6 /* BlockListener.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BlockListener.swift; sourceTree = "<group>"; };
88+
2DD112313DB3181E0851EE46 /* UserActions.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = UserActions.md; sourceTree = "<group>"; };
8789
2DD112BDA8EA0262BDA4744C /* BlockchainMonitor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BlockchainMonitor.swift; sourceTree = "<group>"; };
8890
2DD1133AED83E5E97DBC455F /* Primitives.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = Primitives.md; sourceTree = "<group>"; };
8991
2DD11372CB28789C64A0F55F /* BlockNotifierBasedBlockListener.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BlockNotifierBasedBlockListener.swift; sourceTree = "<group>"; };
@@ -242,6 +244,7 @@
242244
2DD11A364D265C16AF639C21 /* ChannelManager.md */,
243245
2DD11896B49A9872990F4B75 /* Coordination.md */,
244246
2DD11071A3A772E151D7B6A1 /* BlockNotifier.md */,
247+
2DD112313DB3181E0851EE46 /* UserActions.md */,
245248
);
246249
path = Documentation;
247250
sourceTree = "<group>";
@@ -470,6 +473,7 @@
470473
2DD11FD9D863B2994D8DF3CB /* ChannelManager.md in Sources */,
471474
2DD11E177CCCC9E9C4D3E949 /* Coordination.md in Sources */,
472475
2DD110E9D0F00206FA1686B4 /* BlockNotifier.md in Sources */,
476+
2DD11F50EF7D9C09EF5A869B /* UserActions.md in Sources */,
473477
);
474478
runOnlyForDeploymentPostprocessing = 0;
475479
};

Swift Rust FFI/Demonstration.swift

+37-29
Original file line numberDiff line numberDiff line change
@@ -17,58 +17,65 @@ class Demonstration {
1717
public static var peer: Peer?
1818
static var channelManager: ChannelManager?
1919

20-
static func setupPeerManager() {
20+
static func setupPeerManager() -> Promise<Void> {
2121

2222
let privateKey = Data.init(base64Encoded: "ERERERERERERERERERERERERERERERERERERERERERE=")!;
2323
let ephemeralPrivateKey = Data.init(base64Encoded: "EhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhI=")!;
2424
let remotePublicKey = Data.init(base64Encoded: "Ao11AN1MEmhdH1aLTCtQSOhTS4czGfOo2qYStGkTLsf3")!;
2525
let alexPublicKey = Data.init(base64Encoded: "AnRVrvhFPZL0cGtWC2FSfMIX3fFNpBdw6O1mBxkKGFG4")!;
2626
let localPublicKey = Data.init(base64Encoded: "Ai/bcTpKVRYmMWTmDDLOvG9MrW5v7xRNY5vXzcsLIPZZ")!;
2727

28-
let peerManager = PeerManager(privateKey: privateKey, ephemeralSeed: ephemeralPrivateKey)
28+
return self.setupChannelManager().done { manager in
29+
let peerManager = PeerManager(privateKey: privateKey, ephemeralSeed: ephemeralPrivateKey, channelManager: manager.cChannelManager!)
2930

3031

31-
// set up block listener
32-
let chainWatchInterface = peerManager.routingMessageHandler!.cChainWatchInterface
33-
let blockListener = BlockNotifierBasedBlockListener(chainWatchInterface: chainWatchInterface)
32+
// set up block listener
33+
let chainWatchInterface = peerManager.routingMessageHandler!.cChainWatchInterface
34+
let blockListener = BlockNotifierBasedBlockListener(chainWatchInterface: chainWatchInterface)
3435

35-
// set up chain monitor
36-
let chainMonitor = BlockchainMonitor()
37-
chainMonitor.listener = blockListener // connect the two
38-
chainMonitor.monitor() // off we go
36+
// set up chain monitor
37+
let chainMonitor = BlockchainMonitor()
38+
chainMonitor.listener = blockListener // connect the two
39+
chainMonitor.monitor() // off we go
3940

40-
/*
41-
// a connection to be discarded
42-
peerManager.initiateOutboundConnection(remotePublicKey: remotePublicKey)
41+
/*
42+
// a connection to be discarded
43+
peerManager.initiateOutboundConnection(remotePublicKey: remotePublicKey)
4344

44-
// a custom peer to be discarded
45-
print("Creating Google Peer")
46-
let googleClient = TCPClient(address: "google.com", port: 443)
47-
let fakePeer = CustomPeer(tcpClient: googleClient)
48-
fakePeer.name = "Google"
49-
*/
45+
// a custom peer to be discarded
46+
print("Creating Google Peer")
47+
let googleClient = TCPClient(address: "google.com", port: 443)
48+
let fakePeer = CustomPeer(tcpClient: googleClient)
49+
fakePeer.name = "Google"
50+
*/
5051

5152

52-
print("Creating Alex Bosworth peer")
53-
let tcpClient = TCPClient(address: "testnet-lnd.yalls.org", port: 9735)
54-
let peer = CustomPeer(tcpClient: tcpClient)
55-
peer.name = "Alex"
56-
peer.publicKey = alexPublicKey
53+
print("Creating Alex Bosworth peer")
54+
let tcpClient = TCPClient(address: "testnet-lnd.yalls.org", port: 9735)
55+
let peer = CustomPeer(tcpClient: tcpClient)
56+
peer.name = "Alex"
57+
peer.publicKey = alexPublicKey
5758

58-
// print("Creating local peer")
59-
// let tcpClient = TCPClient(address: "127.0.0.1", port: 1337)
60-
// let peer = CustomPeer(tcpClient: tcpClient)
61-
// peer.name = "Local"
59+
// print("Creating local peer")
60+
// let tcpClient = TCPClient(address: "127.0.0.1", port: 1337)
61+
// let peer = CustomPeer(tcpClient: tcpClient)
62+
// peer.name = "Local"
6263

63-
self.peer = peer;
64-
peerManager.initiateOutboundConnection(remotePublicKey: alexPublicKey, peer: peer)
64+
self.peer = peer;
65+
peerManager.initiateOutboundConnection(remotePublicKey: alexPublicKey, peer: peer)
66+
67+
}
6568
}
6669

6770
enum BlockchainFetchError: Error {
6871
case didntWork
6972
}
7073

7174
static func setupChannelManager() -> Promise<ChannelManager> {
75+
if let channelManager = self.channelManager {
76+
return Promise.value(channelManager)
77+
}
78+
7279
let heightPromise = Promise { (resolver: Resolver<UInt>) in
7380
let latestBlockUrl = "https://test.bitgo.com/api/v2/tbtc/public/block/latest"
7481
AF.request(latestBlockUrl).responseJSON { response in
@@ -96,6 +103,7 @@ class Demonstration {
96103
let logger = Logger()
97104
print("Instantiating Swift ChannelManager")
98105
let manager = ChannelManager(privateKey: privateKey, logger: logger, currentBlockchainHeight: height)
106+
self.channelManager = manager
99107
return manager
100108
}
101109
}

Swift Rust FFI/LDK/ChannelManager.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import PromiseKit
88

99
class ChannelManager {
1010

11-
private var cChannelManager: LDKChannelManager?
11+
var cChannelManager: LDKChannelManager?
1212
// private var inMemoryChannelKeys: LDKInMemoryChannelKeys?
1313

1414
private var keyDerivationParamA: UInt64 = 0

Swift Rust FFI/LDK/PeerManager.swift

+40-2
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,11 @@ class PeerManager {
1919

2020
private var tickPromise: Guarantee<Void>?
2121

22+
private var peerCount: UInt = 0
23+
2224
// private var cSecretKey: LDKSecretKey;
2325

24-
init(privateKey: Data, ephemeralSeed: Data) {
26+
init(privateKey: Data, ephemeralSeed: Data, channelManager: LDKChannelManager) {
2527
// let privateKeyPointer = RawLDKTypes.dataToPointer(data: privateKey)
2628
// let ephemeralSeedPointer = RawLDKTypes.dataToPointer(data: ephemeralSeed)
2729
// self.cPeerManager = peer_manager_create(privateKeyPointer, ephemeralSeedPointer)
@@ -33,6 +35,10 @@ class PeerManager {
3335
self.logger = Logger()
3436

3537
self.channelMessageHandler = ChannelMessageHandler()
38+
let channelManagerPointer = withUnsafePointer(to: channelManager) { (pointer: UnsafePointer<LDKChannelManager>) in
39+
pointer
40+
}
41+
let channelMessageHandler = ChannelManager_as_ChannelMessageHandler(channelManagerPointer)
3642
self.routingMessageHandler = RoutingMessageHandler(logger: self.logger!)
3743

3844
// let chainWatchInterface = ChainWatchInterfaceUtil_new(LDKNetwork_Testnet)
@@ -42,7 +48,8 @@ class PeerManager {
4248
// let blockNotifier = BlockNotifier_new(ChainWatchInterfaceUtil_as_ChainWatchInterface(chainWatchInterfacePointer))
4349

4450

45-
let messageHandler = MessageHandler_new(self.channelMessageHandler!.cMessageHandler!, routingMessageHandler!.cRoutingMessageHandler!)
51+
let messageHandler = MessageHandler_new(channelMessageHandler, routingMessageHandler!.cRoutingMessageHandler!)
52+
// let messageHandler = MessageHandler_new(self.channelMessageHandler!.cMessageHandler!, routingMessageHandler!.cRoutingMessageHandler!)
4653

4754

4855
let ourNodeSecret = LDKSecretKey(bytes: privateKeyBytes);
@@ -57,13 +64,44 @@ class PeerManager {
5764
// DispatchQueue.global(qos: .background).async {
5865
// self.forceTick()
5966
// }
67+
68+
self.monitorPeerCount();
69+
6070
}
6171

6272
public func singleTick() {
6373
// TODO: fix
6474
// peer_force_tick(self.cPeerManager);
6575
}
6676

77+
private func monitorPeerCount() {
78+
let peerManagerPointer = withUnsafePointer(to: self.cPeerManager) { pointer in
79+
pointer
80+
}
81+
let peers: LDKCVecTempl_PublicKey = PeerManager_get_peer_node_ids(peerManagerPointer);
82+
let peerCount = peers.datalen;
83+
if (peerCount > self.peerCount) {
84+
self.peerConnected()
85+
}
86+
87+
let backgroundQueue = DispatchQueue.global(qos: .background);
88+
89+
Promise<Void> { seal in
90+
self.peerCount = peerCount;
91+
seal.fulfill(())
92+
}.then(on: backgroundQueue) {
93+
after(seconds: 1) // wait five seconds
94+
}.done {
95+
self.monitorPeerCount()
96+
}
97+
}
98+
99+
private func peerConnected() {
100+
Demonstration.contentView?.isConnecting = false
101+
Demonstration.contentView?.isConnected = true
102+
Demonstration.logInUI(message: "Peer connected")
103+
}
104+
67105
private func forceTick() -> Guarantee<Void> {
68106

69107
guard let promise = self.tickPromise else {

0 commit comments

Comments
 (0)