mirror of
https://github.com/ElementsProject/lightning.git
synced 2025-01-19 05:44:12 +01:00
docs: Add docs on code generation
This commit is contained in:
parent
7153beff28
commit
f4efe6c899
138
doc/dev/contributors/codegen.md
Normal file
138
doc/dev/contributors/codegen.md
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
# Code Generation
|
||||||
|
|
||||||
|
The CLN project has a multitude of interfaces, most of which are
|
||||||
|
generated from an abstract schema:
|
||||||
|
|
||||||
|
- Wire format for peer-to-peer communication: this is the binary
|
||||||
|
format that is specific by the [LN spec][spec]. It uses the
|
||||||
|
[generate-wire.py][generate-wire.py] script to parse the (faux) CSV
|
||||||
|
files that are automatically extrated from the specification and
|
||||||
|
writes C source code files that are then used internally to encode
|
||||||
|
and decode messages, as well as provide print functions for the
|
||||||
|
messages.
|
||||||
|
|
||||||
|
- Wire format for inter-daemon communication: CLN follows a
|
||||||
|
multi-daemon architecture, making communication explicit across
|
||||||
|
daemons. For this inter-daemon communication we use a slightly
|
||||||
|
altered message format from the [LN spec][spec]. The changes are 1)
|
||||||
|
addition of FD passing semantics to allow establishing a new
|
||||||
|
connection between daemons (communication uses
|
||||||
|
[socketpair][socketpair]s, so no `connect`), and 2) change the
|
||||||
|
message length prefix from `u16` to `u32`, allowing for messages
|
||||||
|
larger than 65Kb. The CSV files are with the respective sub-daemon
|
||||||
|
and also use [generate-wire.py][generate-wire.py] to generate
|
||||||
|
encoding, decoding and printing functions.
|
||||||
|
|
||||||
|
- We describe the JSON-RPC using [JSON Schema][jschema] in the
|
||||||
|
[`doc/schemas`][doc-schemas] directory. Each method has a
|
||||||
|
`.request.json` for the request message, and a `.schema.json` for
|
||||||
|
the response (the mismatch is historical and will eventually be
|
||||||
|
addressed). During tests the `pytest` target will verify responses,
|
||||||
|
however the JSON-RPC methods are _not_ generated (yet?). We do
|
||||||
|
generate various client stubs for languages, using the
|
||||||
|
[`msggen`][msggen] tool. More on the generated stubs and utilities
|
||||||
|
below.
|
||||||
|
|
||||||
|
## Man pages
|
||||||
|
|
||||||
|
The [manpages][man] are partially generated from the JSON schemas
|
||||||
|
using the [`fromschema`][fromschema] tool. It reads the request schema
|
||||||
|
and fills in the manpage between two markers:
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
[comment]: # (GENERATE-FROM-SCHEMA-START)
|
||||||
|
...
|
||||||
|
[comment]: # (GENERATE-FROM-SCHEMA-END)
|
||||||
|
```
|
||||||
|
|
||||||
|
!!! note
|
||||||
|
|
||||||
|
Some of this functionality overlaps with [`msggen`][msggen] (parsing the Schemas)
|
||||||
|
and [blockreplace.py][blockreplace.py] (filling in the template). It
|
||||||
|
is likely that this will eventually be merged.
|
||||||
|
|
||||||
|
[blockreplace.py]: https://github.com/ElementsProject/lightning/blob/master/devtools/blockreplace.py
|
||||||
|
[man]: ../../reference/
|
||||||
|
[fromschema]: https://github.com/ElementsProject/lightning/blob/master/tools/fromschema.py
|
||||||
|
|
||||||
|
## `msggen`
|
||||||
|
|
||||||
|
`msggen` is used to generate JSON-RPC client stubs, and converters
|
||||||
|
between in-memory formats and the JSON format. In addition, by
|
||||||
|
chaining some of these we can expose a [grpc][grpc] interface that
|
||||||
|
matches the JSON-RPC interface. This conversion chain is implemented
|
||||||
|
in the [grpc-plugin][grpc-plugin]
|
||||||
|
|
||||||
|
|
||||||
|
<figure markdown>
|
||||||
|
```mermaid
|
||||||
|
graph LR
|
||||||
|
A[JSON schema];
|
||||||
|
A --> B[cln-rpc];
|
||||||
|
B --> B1[Request Structs];
|
||||||
|
B --> B2[Response Structs];
|
||||||
|
B --> B3[Method stubs];
|
||||||
|
|
||||||
|
A --> C[cln-grpc];
|
||||||
|
C --> C1[Protobuf File];
|
||||||
|
C --> C2[In-memory conversion];
|
||||||
|
C --> C3[Service Implementation];
|
||||||
|
```
|
||||||
|
<figcaption>Artifacts generated from the JSON Schemas using `msggen`</figcaption>
|
||||||
|
</figure>
|
||||||
|
|
||||||
|
### `cln-rpc`
|
||||||
|
|
||||||
|
We use `msggen` to generate the Rust bindings crate
|
||||||
|
[`cln-rpc`][cln-rpc]. These bindings contain the stubs for the
|
||||||
|
JSON-RPC methods, as well as types for the request and response
|
||||||
|
structs. The [generator code][cln-rpc-gen] maps each abstract JSON-RPC
|
||||||
|
type to a Rust type, minimizing size (e.g., binary data is
|
||||||
|
hex-decoded).
|
||||||
|
|
||||||
|
The calling pattern follows the `call(req_obj) -> resp_obj` format,
|
||||||
|
and the individual arguments are not expanded. For more ergonomic
|
||||||
|
handling of generic requests and responses we also define the
|
||||||
|
`Request` and `Response` enumerations, so you can hand them to a
|
||||||
|
generic function without having to resort to dynamic dispatch.
|
||||||
|
|
||||||
|
The remainder of the crate implements an async/await JSON-RPC client,
|
||||||
|
that can deal with the Unix Domain Socket [transport][man:json-rpc]
|
||||||
|
used by CLN.
|
||||||
|
|
||||||
|
### `cln-grpc`
|
||||||
|
|
||||||
|
The `cln-grpc` crate is mostly used to provide the primitives to build
|
||||||
|
the `grpc-plugin`. As mentioned above, the grpc functionality relies on a chain of generated parts:
|
||||||
|
|
||||||
|
- First `msggen` is used to generate the [protobuf file][proto],
|
||||||
|
containing the service definition with the method stubs, and the types
|
||||||
|
referenced by those stubs.
|
||||||
|
- Next it generates the `convert.rs` file which is used to convert
|
||||||
|
the structs for in-memory representation from `cln-rpc` into the
|
||||||
|
corresponding protobuf structs.
|
||||||
|
- Finally `msggen` generates the `server.rs` file which can be bound
|
||||||
|
to a grpc endpoint listening for incoming grpc requests, and it
|
||||||
|
will convert the request and forward it to the JSON-RPC. Upon
|
||||||
|
receiving the response it gets converted back into a grpc response
|
||||||
|
and sent back.
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
graph LR
|
||||||
|
A[grpc client] --> B[grpc server] -->|convert.rs| C[cln-rpc] --> D[lightningd];
|
||||||
|
D --> C -->|convert.rs| B --> A;
|
||||||
|
```
|
||||||
|
|
||||||
|
[proto]: https://github.com/ElementsProject/lightning/blob/master/cln-grpc/proto/node.proto
|
||||||
|
[man:json-rpc]: ../../lightningd-rpc.7.md
|
||||||
|
[cln-rpc-gen]: https://github.com/ElementsProject/lightning/blob/master/contrib/msggen/msggen/gen/rust.py
|
||||||
|
[spec]: https://github.com/lightning/bolts
|
||||||
|
[generate-wire.py]: https://github.com/ElementsProject/lightning/blob/master/tools/generate-wire.py
|
||||||
|
[socketpair]: https://man7.org/linux/man-pages/man2/socketpair.2.html
|
||||||
|
[jschema]: https://json-schema.org/
|
||||||
|
[doc-schemas]: https://github.com/ElementsProject/lightning/tree/master/doc/schemas
|
||||||
|
[msggen]: https://github.com/ElementsProject/lightning/tree/master/contrib/msggen
|
||||||
|
[grpc]: https://grpc.io/
|
||||||
|
[cln-grpc]: https://docs.rs/cln-grpc/0.1.1/cln_grpc/
|
||||||
|
[grpc-plugin]: https://github.com/ElementsProject/lightning/tree/master/plugins/grpc-plugin
|
||||||
|
[cln-rpc]: https://github.com/ElementsProject/lightning/tree/master/cln-rpc
|
Loading…
Reference in New Issue
Block a user