|
| 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