Add bindings README
authorMatt Corallo <git@bluematt.me>
Thu, 23 Jul 2020 19:14:44 +0000 (15:14 -0400)
committerMatt Corallo <git@bluematt.me>
Fri, 11 Sep 2020 02:03:32 +0000 (22:03 -0400)
lightning-c-bindings/README.md [new file with mode: 0644]

diff --git a/lightning-c-bindings/README.md b/lightning-c-bindings/README.md
new file mode 100644 (file)
index 0000000..fa33a9f
--- /dev/null
@@ -0,0 +1,229 @@
+The wrapper crate and C/C++ Headers in this folder are auto-generated from the Rust-Lightning
+source by the c-bindings-gen crate contained in the source tree and
+[cbindgen](https://github.com/eqrion/cbindgen). They are intended to be used as a base for building
+language-specific bindings, and are thus incredibly low-level and may be difficult to work with
+directly.
+
+In other words, if you're reading this, you're either writing bindings for a new language, or
+you're in the wrong place - individual language bindings should come with their own documentation.
+
+LDK C Bindings
+==============
+
+The C bindings available at include/lightning.h require inclusion of include/rust_types.h first.
+
+All of the Rust-Lightning types are mapped into C equivalents which take a few forms, with the C
+type getting an `LDK` prefix to their native Rust type names.
+
+#### Structs
+Structs are mapped into a simple wrapper containing a pointer to the native Rust-Lightning object
+and a flag to indicate whether the object is owned or only a reference. Such mappings usually
+generate a `X_free` function which must be called to release the allocated resources. Note that
+calling `X_free` will do nothing if the underlying pointer is NULL or if the `is_owned` flag is not
+set.
+
+You MUST NOT create such wrapper structs manually, relying instead on constructors which have been
+mapped from equivalent Rust constructors.
+
+Note that, thanks to the is-owned flag and the pointer being NULLable, such structs effectively
+represent `RustType`, `&RustType`, and `Option<RustType>`. Check the corresponding Rust
+documentation for the function or struct you are using to ensure you use the correct call semantics.
+The passed struct must match the call semantics or an assertion failure or NULL pointer dereference
+may occur.
+
+For example, this is the mapping of ChannelManager.
+```c
+typedef struct MUST_USE_STRUCT LDKChannelManager {
+   /** ... */
+   LDKnativeChannelManager *inner;
+   bool is_owned;
+} LDKChannelManager;
+```
+
+#### Traits
+Traits are mapped into a concrete struct containing a void pointer (named `this_arg` and a jump
+table listing the functions which the trait must implement. The void pointer may be set to any value
+and is never interpreted (or dereferenced) by the bindings logic in any way. It is passed as the
+first argument to all function calls in the trait. You may wish to use it as a pointer to your own
+internal data structure, though it may also occasionally make sense to e.g. cast a file descriptor
+into a void pointer and use it to track a socket.
+
+This should remind you of a C++ vtable, only written out by hand and with the class only containing
+a pointer, instead of the regular class data.
+
+Each trait additionally contains `free` and `clone` function pointers, which may be NULL. The `free`
+function is passed the void pointer when the object is `Drop`ed in Rust. The `clone` function is
+passed the void pointer when the object is `Clone`ed in Rust, returning a new void pointer for the
+new object. If the `free` pointer is NULL, you will not receive any notification when the trait
+object is no longer needed. If the `clone` pointer is NULL, we assume that the trait object may be
+`memcpy()`'d to create copies. Note that if you release resources with `free` without implementing
+`clone`, you will likely end up with use-after-free bugs (as copies of the original this_arg value
+may still exist, unbeknownst to you).
+
+For example, `LDKSocketDescriptor` is mapped as follows:
+```c
+typedef struct LDKSocketDescriptor {
+   void *this_arg;
+   /** ... */
+   uintptr_t (*send_data)(void *this_arg, LDKu8slice data, bool resume_read);
+   /** ... */
+   void (*disconnect_socket)(void *this_arg);
+   bool (*eq)(const void *this_arg, const void *other_arg);
+   uint64_t (*hash)(const void *this_arg);
+   void *(*clone)(const void *this_arg);
+   void (*free)(void *this_arg);
+} LDKSocketDescriptor;
+```
+
+##### Rust Trait Implementations
+Rust structs that implement a trait result in the generation of an `X_as_Y` function, which takes a
+C struct wrapping the Rust native object and returns a generated trait object. Such generated
+objects are only valid as long as the original Rust native object has not been `free`'d or moved as
+a part of a Rust function call (ie continues to be owned by the C struct). For example, to use an
+`LDKInMemoryChannelKeys` as a `ChannelKeys`, `InMemoryChannelKeys_as_ChannelKeys` is exposed:
+
+```c
+LDKChannelKeys InMemoryChannelKeys_as_ChannelKeys(const LDKInMemoryChannelKeys *this_arg);
+```
+
+#### Enums
+Rust "unitary" enums are mapped simply as an equivalent C enum; however, some Rust enums have
+variants which contain payloads. Such enums are mapped automatically by cbindgen as a tag which
+indicates the type and a union which holds the relevant fields for a given tag. An `X_free` function
+is provided for the enum as a whole which automatically frees the correct fields for a give tag, and
+a `Sentinel` tag is provided which causes the free function to do nothing (but which must never
+appear in an enum when accessed by Rust code). The `Sentinel` tag is used by the C++ wrapper classes
+to allow moving the ownership of an enum while invalidating the old copy.
+
+For example, the unitary enum `LDKChannelMonitorUpdateErr` is mapped as follows:
+```c
+typedef enum LDKChannelMonitorUpdateErr {
+   /** .. */
+   LDKChannelMonitorUpdateErr_TemporaryFailure,
+   /** .. */
+   LDKChannelMonitorUpdateErr_PermanentFailure,
+   /** .. */
+   LDKChannelMonitorUpdateErr_Sentinel,
+} LDKChannelMonitorUpdateErr;
+```
+
+and the non-unitary enum LDKErrorAction is mapped as follows:
+```c
+typedef enum LDKErrorAction_Tag {
+   /** .. */
+   LDKErrorAction_DisconnectPeer,
+   /** .. */
+   LDKErrorAction_IgnoreError,
+   /** .. */
+   LDKErrorAction_SendErrorMessage,
+   /** .. */
+   LDKErrorAction_Sentinel,
+} LDKErrorAction_Tag;
+
+typedef struct LDKErrorAction_LDKDisconnectPeer_Body {
+   LDKErrorMessage msg;
+} LDKErrorAction_LDKDisconnectPeer_Body;
+
+typedef struct LDKErrorAction_LDKSendErrorMessage_Body {
+   LDKErrorMessage msg;
+} LDKErrorAction_LDKSendErrorMessage_Body;
+
+typedef struct LDKErrorAction {
+   LDKErrorAction_Tag tag;
+   union {
+      LDKErrorAction_LDKDisconnectPeer_Body disconnect_peer;
+      LDKErrorAction_LDKSendErrorMessage_Body send_error_message;
+   };
+} LDKErrorAction;
+```
+
+#### Functions
+Struct member functions are mapped as `Struct_function_name` and take a pointer to the mapped struct
+as their first argument. Free-standing functions are mapped simply as `function_name` and take the
+relevant mapped type arguments.
+
+Functions which return `&OpaqueRustType` and which return `OpaqueRustType` are both mapped to a
+function returning an owned wrapper struct. The `is_owned` flag (see above) will be set to indicate
+that the pointed-to Rust object is owned or only a reference. Thus, when implementing a function
+which Rust will call or calling a Rust function, you should check the Rust documentation for the
+function to determine whether an owned or referenced object is expected or returned.
+
+Similarly, when a function takes an `Option<RustType>` as a parameter or a return value, the C type
+is the same as if it took only `RustType`, with the `inner` field set to NULL to indicate None. For
+example, `ChannelManager_create_channel` takes an `Option<LDKUserConfig>` not an `LDKUserConfig`,
+but its definition is:
+```c
+MUST_USE_RES ... ChannelManager_create_channel(const LDKChannelManager *this_arg, ..., LDKUserConfig override_config);
+```
+
+#### Containers
+Various containers (Tuples, Vecs, Results, etc) are mapped into C structs of the form
+`LDKCContainerType_ContainerElementsZ`. Inner fields are often pointers, and in the case of
+primitive types, these may be allocated in C using the system allocator. See [the Rust docs on your
+platform's default System allocator](https://doc.rust-lang.org/std/alloc/struct.System.html) for
+ which allocator you must use. Recursive containers are possible, and simply replace the
+`ContainerElements` part with `InnerContainerType_InnerContainerElementsZ`, eg
+`LDKCResult_C2Tuple_SignatureCVec_SignatureZZNoneZ` represents a
+`Result<(Signature, Vec<Signature>), ()>`.
+
+#### Notes
+As the bindings are auto-generated, the best resource for documentation on them is the native Rust
+docs available via `cargo doc` or [docs.rs/lightning](https://docs.rs/lightning).
+
+The memory model is largely the Rust memory model and not a native C-like memory model. Thus,
+function parameters are largely only ever passed by reference or by move, with pass-by-copy
+semantics only applying to primitive types. However, because the underlying types are largely
+pointers, the same function signature may imply two different memory ownership semantics. Thus, you
+MUST read the Rust documentation while using the C bindings. For functions which take arguments
+where ownership is moved to the function scope, the corresponding `X_free` function MUST NOT be
+called on the object, whereas for all other objects, `X_free` MUST be used to free resources.
+
+LDK C++ Bindings
+================
+
+The C++ bindings available at include/lightningpp.hpp require extern "C" inclusion of lightning.h
+and rust_types.h first. They represent thin wrappers around the C types which provide a few
+C++-isms to make memory model correctness easier to achieve. They provide:
+ * automated destructors which call the relevant `X_free` C functions,
+ * move constructors both from C++ classes and the original C struct, with the original object
+   cleared to ensure destruction/`X_free` calls do not cause a double-free.
+ * Move semantics via the () operator, returning the original C struct and clearing the C++ object.
+   This allows calls such as `C_function(cpp_object)` which work as expected with move semantics.
+
+In general, you should prefer to use the C++ bindings if possible, as they make memory leaks and
+other violations somewhat easier to avoid. Note that, because the C functions are not redefined in
+C++, all functions return the C type. Thus, you must bind returned values to the equivalent C++ type
+(replacing `LDKX` with `LDK::X`) to ensure the destructor is properly run. A demonstration of such
+usage is available at [demo.cpp](demo.cpp).
+
+Gotchas
+=======
+
+There are a few gotchas around future changes to Rust-Lightning which the bindings may not support.
+These include:
+ * Any trait method which returns a reference to a struct or inner variable cannot be called in
+   parallel. This is because such functions always return a local variable stored inside the trait,
+   with a call through a function pointer to get the local variable set correctly. Automatically
+   generated setter functions have comments describing the potential race conditions in their
+   definition.
+
+   For example, the `ChannelKeys::pubkeys() -> &ChannelPublicKeys` function is mapped as this:
+
+   ```c
+   typedef struct LDKChannelKeys {
+      ...
+      LDKChannelPublicKeys pubkeys;
+      /** ... */
+      void (*set_pubkeys)(const LDKChannelKeys*);
+         ...
+   } LDKChannelKeys;
+   ```
+   
+**It is highly recommended that you test any code which relies on the C (or C++) bindings in
+valgrind, AddressSanitizer, MemorySanitizer, or other similar tools to ensure correctness.**
+
+Note that after running `genbindings.sh`, if possible, the static lib in target/debug (eg
+target/debug/liblightning.a) will be linked with address sanitizer. In order to build against it,
+you will need to link with `clang` with `-fsanitize=address` with the same version of LLVM as
+`rustc`'s LLVM. If `genbindings.sh` failed to find a matching `clang` or you are building on an
+unsupported platform, a warning noting that address sanitizer is not available will be printed.