Skip to content

Commit 4f6f34f

Browse files
committed
Add bindings README
1 parent 9f0fa04 commit 4f6f34f

File tree

1 file changed

+229
-0
lines changed

1 file changed

+229
-0
lines changed

lightning-c-bindings/README.md

Lines changed: 229 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,229 @@
1+
The wrapper crate and C/C++ Headers in this folder are auto-generated from the Rust-Lightning
2+
source by the c-bindings-gen crate contained in the source tree and
3+
[cbindgen](https://github.com/eqrion/cbindgen). They are intended to be used as a base for building
4+
language-specific bindings, and are thus incredibly low-level and may be difficult to work with
5+
directly.
6+
7+
In other words, if you're reading this, you're either writing bindings for a new language, or
8+
you're in the wrong place - individual language bindings should come with their own documentation.
9+
10+
LDK C Bindings
11+
==============
12+
13+
The C bindings available at include/lightning.h require inclusion of include/rust_types.h first.
14+
15+
All of the Rust-Lightning types are mapped into C equivalents which take a few forms, with the C
16+
type getting an `LDK` prefix to their native Rust type names.
17+
18+
#### Structs
19+
Structs are mapped into a simple wrapper containing a pointer to the native Rust-Lightning object
20+
and a flag to indicate whether the object is owned or only a reference. Such mappings usually
21+
generate a `X_free` function which must be called to release the allocated resources. Note that
22+
calling `X_free` will do nothing if the underlying pointer is NULL or if the `is_owned` flag is not
23+
set.
24+
25+
You MUST NOT create such wrapper structs manually, relying instead on constructors which have been
26+
mapped from equivalent Rust constructors.
27+
28+
Note that, thanks to the is-owned flag and the pointer being NULLable, such structs effectively
29+
represent `RustType`, `&RustType`, and `Option<RustType>`. Check the corresponding Rust
30+
documentation for the function or struct you are using to ensure you use the correct call semantics.
31+
The passed struct must match the call semantics or an assertion failure or NULL pointer dereference
32+
may occur.
33+
34+
For example, this is the mapping of ChannelManager.
35+
```c
36+
typedef struct MUST_USE_STRUCT LDKChannelManager {
37+
/** ... */
38+
LDKnativeChannelManager *inner;
39+
bool is_owned;
40+
} LDKChannelManager;
41+
```
42+
43+
#### Traits
44+
Traits are mapped into a concrete struct containing a void pointer (named `this_arg` and a jump
45+
table listing the functions which the trait must implement. The void pointer may be set to any value
46+
and is never interpreted (or dereferenced) by the bindings logic in any way. It is passed as the
47+
first argument to all function calls in the trait. You may wish to use it as a pointer to your own
48+
internal data structure, though it may also occasionally make sense to e.g. cast a file descriptor
49+
into a void pointer and use it to track a socket.
50+
51+
This should remind you of a C++ vtable, only written out by hand and with the class only containing
52+
a pointer, instead of the regular class data.
53+
54+
Each trait additionally contains `free` and `clone` function pointers, which may be NULL. The `free`
55+
function is passed the void pointer when the object is `Drop`ed in Rust. The `clone` function is
56+
passed the void pointer when the object is `Clone`ed in Rust, returning a new void pointer for the
57+
new object. If the `free` pointer is NULL, you will not receive any notification when the trait
58+
object is no longer needed. If the `clone` pointer is NULL, we assume that the trait object may be
59+
`memcpy()`'d to create copies. Note that if you release resources with `free` without implementing
60+
`clone`, you will likely end up with use-after-free bugs (as copies of the original this_arg value
61+
may still exist, unbeknownst to you).
62+
63+
For example, `LDKSocketDescriptor` is mapped as follows:
64+
```c
65+
typedef struct LDKSocketDescriptor {
66+
void *this_arg;
67+
/** ... */
68+
uintptr_t (*send_data)(void *this_arg, LDKu8slice data, bool resume_read);
69+
/** ... */
70+
void (*disconnect_socket)(void *this_arg);
71+
bool (*eq)(const void *this_arg, const void *other_arg);
72+
uint64_t (*hash)(const void *this_arg);
73+
void *(*clone)(const void *this_arg);
74+
void (*free)(void *this_arg);
75+
} LDKSocketDescriptor;
76+
```
77+
78+
##### Rust Trait Implementations
79+
Rust structs that implement a trait result in the generation of an `X_as_Y` function, which takes a
80+
C struct wrapping the Rust native object and returns a generated trait object. Such generated
81+
objects are only valid as long as the original Rust native object has not been `free`'d or moved as
82+
a part of a Rust function call (ie continues to be owned by the C struct). For example, to use an
83+
`LDKInMemoryChannelKeys` as a `ChannelKeys`, `InMemoryChannelKeys_as_ChannelKeys` is exposed:
84+
85+
```c
86+
LDKChannelKeys InMemoryChannelKeys_as_ChannelKeys(const LDKInMemoryChannelKeys *this_arg);
87+
```
88+
89+
#### Enums
90+
Rust "unitary" enums are mapped simply as an equivalent C enum; however, some Rust enums have
91+
variants which contain payloads. Such enums are mapped automatically by cbindgen as a tag which
92+
indicates the type and a union which holds the relevant fields for a given tag. An `X_free` function
93+
is provided for the enum as a whole which automatically frees the correct fields for a give tag, and
94+
a `Sentinel` tag is provided which causes the free function to do nothing (but which must never
95+
appear in an enum when accessed by Rust code). The `Sentinel` tag is used by the C++ wrapper classes
96+
to allow moving the ownership of an enum while invalidating the old copy.
97+
98+
For example, the unitary enum `LDKChannelMonitorUpdateErr` is mapped as follows:
99+
```c
100+
typedef enum LDKChannelMonitorUpdateErr {
101+
/** .. */
102+
LDKChannelMonitorUpdateErr_TemporaryFailure,
103+
/** .. */
104+
LDKChannelMonitorUpdateErr_PermanentFailure,
105+
/** .. */
106+
LDKChannelMonitorUpdateErr_Sentinel,
107+
} LDKChannelMonitorUpdateErr;
108+
```
109+
110+
and the non-unitary enum LDKErrorAction is mapped as follows:
111+
```c
112+
typedef enum LDKErrorAction_Tag {
113+
/** .. */
114+
LDKErrorAction_DisconnectPeer,
115+
/** .. */
116+
LDKErrorAction_IgnoreError,
117+
/** .. */
118+
LDKErrorAction_SendErrorMessage,
119+
/** .. */
120+
LDKErrorAction_Sentinel,
121+
} LDKErrorAction_Tag;
122+
123+
typedef struct LDKErrorAction_LDKDisconnectPeer_Body {
124+
LDKErrorMessage msg;
125+
} LDKErrorAction_LDKDisconnectPeer_Body;
126+
127+
typedef struct LDKErrorAction_LDKSendErrorMessage_Body {
128+
LDKErrorMessage msg;
129+
} LDKErrorAction_LDKSendErrorMessage_Body;
130+
131+
typedef struct LDKErrorAction {
132+
LDKErrorAction_Tag tag;
133+
union {
134+
LDKErrorAction_LDKDisconnectPeer_Body disconnect_peer;
135+
LDKErrorAction_LDKSendErrorMessage_Body send_error_message;
136+
};
137+
} LDKErrorAction;
138+
```
139+
140+
#### Functions
141+
Struct member functions are mapped as `Struct_function_name` and take a pointer to the mapped struct
142+
as their first argument. Free-standing functions are mapped simply as `function_name` and take the
143+
relevant mapped type arguments.
144+
145+
Functions which return `&OpaqueRustType` and which return `OpaqueRustType` are both mapped to a
146+
function returning an owned wrapper struct. The `is_owned` flag (see above) will be set to indicate
147+
that the pointed-to Rust object is owned or only a reference. Thus, when implementing a function
148+
which Rust will call or calling a Rust function, you should check the Rust documentation for the
149+
function to determine whether an owned or referenced object is expected or returned.
150+
151+
Similarly, when a function takes an `Option<RustType>` as a parameter or a return value, the C type
152+
is the same as if it took only `RustType`, with the `inner` field set to NULL to indicate None. For
153+
example, `ChannelManager_create_channel` takes an `Option<LDKUserConfig>` not an `LDKUserConfig`,
154+
but its definition is:
155+
```c
156+
MUST_USE_RES ... ChannelManager_create_channel(const LDKChannelManager *this_arg, ..., LDKUserConfig override_config);
157+
```
158+
159+
#### Containers
160+
Various containers (Tuples, Vecs, Results, etc) are mapped into C structs of the form
161+
`LDKCContainerType_ContainerElementsZ`. Inner fields are often pointers, and in the case of
162+
primitive types, these may be allocated in C using the system allocator. See [the Rust docs on your
163+
platform's default System allocator](https://doc.rust-lang.org/std/alloc/struct.System.html) for
164+
which allocator you must use. Recursive containers are possible, and simply replace the
165+
`ContainerElements` part with `InnerContainerType_InnerContainerElementsZ`, eg
166+
`LDKCResult_C2Tuple_SignatureCVec_SignatureZZNoneZ` represents a
167+
`Result<(Signature, Vec<Signature>), ()>`.
168+
169+
#### Notes
170+
As the bindings are auto-generated, the best resource for documentation on them is the native Rust
171+
docs available via `cargo doc` or [docs.rs/lightning](https://docs.rs/lightning).
172+
173+
The memory model is largely the Rust memory model and not a native C-like memory model. Thus,
174+
function parameters are largely only ever passed by reference or by move, with pass-by-copy
175+
semantics only applying to primitive types. However, because the underlying types are largely
176+
pointers, the same function signature may imply two different memory ownership semantics. Thus, you
177+
MUST read the Rust documentation while using the C bindings. For functions which take arguments
178+
where ownership is moved to the function scope, the corresponding `X_free` function MUST NOT be
179+
called on the object, whereas for all other objects, `X_free` MUST be used to free resources.
180+
181+
LDK C++ Bindings
182+
================
183+
184+
The C++ bindings available at include/lightningpp.hpp require extern "C" inclusion of lightning.h
185+
and rust_types.h first. They represent thin wrappers around the C types which provide a few
186+
C++-isms to make memory model correctness easier to achieve. They provide:
187+
* automated destructors which call the relevant `X_free` C functions,
188+
* move constructors both from C++ classes and the original C struct, with the original object
189+
cleared to ensure destruction/`X_free` calls do not cause a double-free.
190+
* Move semantics via the () operator, returning the original C struct and clearing the C++ object.
191+
This allows calls such as `C_function(cpp_object)` which work as expected with move semantics.
192+
193+
In general, you should prefer to use the C++ bindings if possible, as they make memory leaks and
194+
other violations somewhat easier to avoid. Note that, because the C functions are not redefined in
195+
C++, all functions return the C type. Thus, you must bind returned values to the equivalent C++ type
196+
(replacing `LDKX` with `LDK::X`) to ensure the destructor is properly run. A demonstration of such
197+
usage is available at [demo.cpp](demo.cpp).
198+
199+
Gotchas
200+
=======
201+
202+
There are a few gotchas around future changes to Rust-Lightning which the bindings may not support.
203+
These include:
204+
* Any trait method which returns a reference to a struct or inner variable cannot be called in
205+
parallel. This is because such functions always return a local variable stored inside the trait,
206+
with a call through a function pointer to get the local variable set correctly. Automatically
207+
generated setter functions have comments describing the potential race conditions in their
208+
definition.
209+
210+
For example, the `ChannelKeys::pubkeys() -> &ChannelPublicKeys` function is mapped as this:
211+
212+
```c
213+
typedef struct LDKChannelKeys {
214+
...
215+
LDKChannelPublicKeys pubkeys;
216+
/** ... */
217+
void (*set_pubkeys)(const LDKChannelKeys*);
218+
...
219+
} LDKChannelKeys;
220+
```
221+
222+
**It is highly recommended that you test any code which relies on the C (or C++) bindings in
223+
valgrind, AddressSanitizer, MemorySanitizer, or other similar tools to ensure correctness.**
224+
225+
Note that after running `genbindings.sh`, if possible, the static lib in target/debug (eg
226+
target/debug/liblightning.a) will be linked with address sanitizer. In order to build against it,
227+
you will need to link with `clang` with `-fsanitize=address` with the same version of LLVM as
228+
`rustc`'s LLVM. If `genbindings.sh` failed to find a matching `clang` or you are building on an
229+
unsupported platform, a warning noting that address sanitizer is not available will be printed.

0 commit comments

Comments
 (0)