Commit 9b819f6
feat(gl-sdk): builder-style Node creation, signerless by default
NodeBuilder is the sole public entry point for Node construction
across all foreign bindings. The former free functions register /
recover / connect / register_or_recover are demoted to crate-private
helpers (`*_internal`); foreign-binding consumers go through
`NodeBuilder` exclusively.
Two design rules drive the shape:
1. Naked free functions are hard to extend without semver breaks. A
builder absorbs new modifiers as additional with_* setters —
additive forever.
2. Signer access ≡ root access on the node (self-certifies runes,
mints TLS certs). The SDK must support keyless clients that don't
hold the seed at all (paired devices, browser extensions, hardware
signers). Signerless connect must be a first-class path, not an
afterthought.
Resulting surface:
// Signerless connect — caller has no mnemonic in this process.
// SDK runs no signer; signing happens at the CLN node, a paired
// device, or hardware. The keyless-client model.
let node = NodeBuilder::new(&config).connect(credentials, None)?;
// Signed connect — caller hands the mnemonic per-call, SDK
// spawns a signer for the lifetime of the Node.
let node = NodeBuilder::new(&config).connect(credentials, Some(mnemonic))?;
// Register / recover / register_or_recover require a mnemonic
// by definition (the signer must sign the registration /
// recovery challenge). Mnemonic is positional, not stateful.
let node = NodeBuilder::new(&config)
.with_event_listener(listener)
.register(mnemonic, invite_code)?;
The mnemonic is never stored on the builder. It is a positional
argument on the build call that needs it, so its lifetime is bounded
to that call and there is no half-set state. Modifiers like
with_event_listener live on the builder; secrets do not.
Surface
- NodeBuilder::new(config) — collects config + optional modifiers,
no I/O.
- with_event_listener(listener) — fluent setter that returns a fresh
`Arc<NodeBuilder>` carrying the new listener; the original builder
is unchanged. No interior mutability.
- register(mnemonic, invite_code) — mnemonic required.
- recover(mnemonic) — mnemonic required.
- register_or_recover(mnemonic, invite_code) — mnemonic required.
- connect(credentials, mnemonic: Option<String>) — mnemonic optional;
None produces a signerless Node.
Builder shape
- Two fields, both immutable after construction: `config:
Arc<Config>` and `event_listener: Option<Arc<dyn NodeEventListener>>`.
No `Mutex`, no `RefCell`, no interior mutability anywhere — the
builder is a value, not a state machine.
- `with_*` setters take `self: Arc<Self>` and return a new
`Arc<NodeBuilder>` with the modified field, sharing the rest via
`Arc::clone`. Single small allocation per setter call; the rest is
pointer copies.
- The listener is stored as `Arc<dyn NodeEventListener>` so the same
builder can drive multiple builds — each build clones the Arc and
hands it to the resulting Node. (UniFFI's callback lowering hands
us a `Box<dyn Trait>` at the FFI boundary; the setter re-wraps it
via `Arc::from(box)` once.)
Implementation notes
- Node::signerless(credentials) is a new pub (non-UniFFI-export)
Rust constructor. Used by the builder for the None-mnemonic path
and by gl-sdk-napi to back its `new Node(credentials)` constructor
with the same signerless semantics.
- crate::connect_signerless_internal wires Node::signerless into
the lib.rs internals; crate::connect_internal continues to drive
the signed connect via the SDK signer spawn.
- Node::set_event_listener (pub(crate)) takes
`Arc<dyn NodeEventListener>`; spawns a background tokio task that
tails the gRPC event stream and dispatches to listener.on_event.
The task is aborted on Drop and replaced if a new listener is set.
- The polling-style Node::stream_node_events() API stays for callers
who prefer to drive events themselves; the builder route is just a
callback-style alternative that can't miss early events.
Tests migrated
- Python: test_auth_api.py (24 callsites), test_list_payments.py
(6), test_node_methods.py (2).
- Kotlin: AuthApiTest.kt (8), NodeOperationsTest.kt (2),
ListPaymentTest.kt (3), LoggingTest.kt (1). All converted to the
positional-mnemonic-on-build-call shape.
Verified: `cargo build -p gl-sdk -p gl-sdk-node` clean; Python
bindings expose `NodeBuilder` (with the new method signatures) and
`NodeEventListener` and no longer expose the demoted free
functions.1 parent d614086 commit 9b819f6
15 files changed
Lines changed: 810 additions & 284 deletions
File tree
- gitlab
- libs
- gl-sdk-android/lib/src/androidInstrumentedTest/kotlin/com/blockstream/glsdk
- gl-sdk-cli/src
- gl-sdk-napi/src
- gl-sdk
- glsdk
- src
- tests
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
50 | 50 | | |
51 | 51 | | |
52 | 52 | | |
53 | | - | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
54 | 58 | | |
55 | 59 | | |
56 | 60 | | |
| |||
64 | 68 | | |
65 | 69 | | |
66 | 70 | | |
67 | | - | |
68 | | - | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
69 | 79 | | |
Lines changed: 8 additions & 8 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
65 | 65 | | |
66 | 66 | | |
67 | 67 | | |
68 | | - | |
| 68 | + | |
69 | 69 | | |
70 | 70 | | |
71 | 71 | | |
72 | 72 | | |
73 | 73 | | |
74 | | - | |
| 74 | + | |
75 | 75 | | |
76 | 76 | | |
77 | 77 | | |
78 | 78 | | |
79 | 79 | | |
80 | | - | |
| 80 | + | |
81 | 81 | | |
82 | 82 | | |
83 | 83 | | |
| |||
88 | 88 | | |
89 | 89 | | |
90 | 90 | | |
91 | | - | |
| 91 | + | |
92 | 92 | | |
93 | 93 | | |
94 | 94 | | |
| |||
104 | 104 | | |
105 | 105 | | |
106 | 106 | | |
107 | | - | |
| 107 | + | |
108 | 108 | | |
109 | 109 | | |
110 | 110 | | |
111 | 111 | | |
112 | | - | |
| 112 | + | |
113 | 113 | | |
114 | 114 | | |
115 | 115 | | |
| |||
124 | 124 | | |
125 | 125 | | |
126 | 126 | | |
127 | | - | |
| 127 | + | |
128 | 128 | | |
129 | 129 | | |
130 | 130 | | |
| |||
139 | 139 | | |
140 | 140 | | |
141 | 141 | | |
142 | | - | |
| 142 | + | |
143 | 143 | | |
144 | 144 | | |
145 | 145 | | |
| |||
Lines changed: 3 additions & 3 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
63 | 63 | | |
64 | 64 | | |
65 | 65 | | |
66 | | - | |
| 66 | + | |
67 | 67 | | |
68 | 68 | | |
69 | 69 | | |
| |||
84 | 84 | | |
85 | 85 | | |
86 | 86 | | |
87 | | - | |
| 87 | + | |
88 | 88 | | |
89 | 89 | | |
90 | 90 | | |
| |||
107 | 107 | | |
108 | 108 | | |
109 | 109 | | |
110 | | - | |
| 110 | + | |
111 | 111 | | |
112 | 112 | | |
113 | 113 | | |
| |||
Lines changed: 1 addition & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
53 | 53 | | |
54 | 54 | | |
55 | 55 | | |
56 | | - | |
| 56 | + | |
57 | 57 | | |
58 | 58 | | |
59 | 59 | | |
| |||
Lines changed: 2 additions & 2 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
27 | 27 | | |
28 | 28 | | |
29 | 29 | | |
30 | | - | |
| 30 | + | |
31 | 31 | | |
32 | 32 | | |
33 | 33 | | |
| |||
47 | 47 | | |
48 | 48 | | |
49 | 49 | | |
50 | | - | |
| 50 | + | |
51 | 51 | | |
52 | 52 | | |
53 | 53 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
52 | 52 | | |
53 | 53 | | |
54 | 54 | | |
55 | | - | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
56 | 58 | | |
57 | 59 | | |
58 | 60 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
323 | 323 | | |
324 | 324 | | |
325 | 325 | | |
326 | | - | |
327 | | - | |
328 | 326 | | |
329 | 327 | | |
330 | 328 | | |
| |||
337 | 335 | | |
338 | 336 | | |
339 | 337 | | |
340 | | - | |
341 | 338 | | |
342 | 339 | | |
343 | 340 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
503 | 503 | | |
504 | 504 | | |
505 | 505 | | |
506 | | - | |
| 506 | + | |
| 507 | + | |
| 508 | + | |
| 509 | + | |
| 510 | + | |
| 511 | + | |
507 | 512 | | |
508 | 513 | | |
509 | 514 | | |
510 | 515 | | |
511 | 516 | | |
512 | | - | |
| 517 | + | |
513 | 518 | | |
514 | | - | |
| 519 | + | |
515 | 520 | | |
516 | 521 | | |
517 | 522 | | |
| |||
866 | 871 | | |
867 | 872 | | |
868 | 873 | | |
869 | | - | |
870 | | - | |
871 | | - | |
872 | | - | |
873 | 874 | | |
874 | 875 | | |
875 | 876 | | |
| |||
0 commit comments