Skip to content

feat(ffi): pin nim-ffi 0.3.0 and stop the node on destroy - #4111

Open
gmelodie wants to merge 6 commits into
masterfrom
chore/ffi/bump-rc3
Open

feat(ffi): pin nim-ffi 0.3.0 and stop the node on destroy#4111
gmelodie wants to merge 6 commits into
masterfrom
chore/ffi/bump-rc3

Conversation

@gmelodie

@gmelodie gmelodie commented Aug 7, 2026

Copy link
Copy Markdown
Collaborator

Description

nim-ffi 0.3.0 runs the {.ffiDtor.} body on the context recycle path (logos-messaging/nim-ffi#147). That is the first of the two pieces #4108 asks for. This PR pins that release and adds the second piece: logosdelivery_destroy now stops the node.

Until now a host that called logosdelivery_destroy without logosdelivery_stop_node first got a node it could no longer reach but that kept running. nim-ffi recycles the worker thread instead of joining it, so the libp2p switch, the discv5 loop, the REST server and the persistency storage threads survived the destroy for the rest of the process lifetime, while the recycle cleared the event registry under them. The dtor was discard, and the pinned 0.3.0-rc.2 never ran it anyway.

The bump also makes {.ffiExport.} reachable. logosdelivery_version() uses it: the call takes no context, so a host can read the version of a .so before it builds a node.

Changes

logos_delivery.nimble now requires ffi == 0.3.0 by package name. nim-ffi is on the official nimble package list, so the entry moves into the main requires block and leaves the git-URL block. The v0.3.0 tag points at commit b6c17dc8, so nimble.lock and nix/deps.nix keep that revision and its hashes.

logosdelivery_destroy and logosdelivery_stop_node now share one teardown, stopNode, which drops the FFI event listeners and then stops the node while LogosDelivery.isRunning says one runs. logosdelivery_stop_node is therefore idempotent: a second call reports RET_OK and does nothing.

LogosDelivery.isRunning is new in logos_delivery/logos_delivery.nim, next to start and stop. It answers for the whole stack, so the FFI layer no longer reads waku.node.started through three types.

logosdelivery_start_node drops the listeners it registered when start fails. A host that retried a failed start used to stack a second full set of broker listeners, and every event then fanned out twice.

logosdelivery_version() is a new C entry point in library/logos_delivery_api/sync_exports.nim. nim-ffi does not emit {.ffiExport.} procs into the generated abi = c header, so it is declared by hand in library/liblogosdelivery.h next to the event-listener ABI.

tests/ffi/test_ffi_persistency_lifecycle.nim gains a destroy-stops-node case: ctx1 binds a TCP and a discv5 port, is destroyed without a stop, and ctx2 must bind the same two ports. ctx1 had to bind them first, so a failure of the second bind means ctx1 never released them. The case also calls logosdelivery_version before any context exists. The same file had logosdelivery_destroy typed with a callback it lost in #4082, so every destroy step waited 60 s for a callback that never fires; it now uses the real int(void*) signature.

0.3.0 also rejects a call against a ref library that no constructor ever stored, instead of reading the fields of a nil library. LogosDelivery is a ref object, and logosdelivery_create_node hands the host a live context before the constructor runs, so the host holds one even when the constructor fails. The case call-after-failed-ctor creates a context from an invalid config, calls logosdelivery_start_node on it, and expects an error that carries not initialized. logosdelivery_destroy still releases that context, because nim-ffi gates the {.ffiDtor.} body on a stored library. library/README.md states the behaviour under logosdelivery_create_node.

library/README.md records the two limits of the destroy path. The recycle handler drops what the hook returns, so a failed stop is logged and the host still reads RET_OK. nim-ffi cancels the stop at ffiTeardownTimeoutMs (10 s) and frees the library anyway, which leaves the node half stopped. logosdelivery_stop_node stays the call that runs to completion and reports its result.

Impact on hosts: no C signature changes. logosdelivery_destroy now blocks its caller for as long as the stop takes, bounded by 2 * ffiRecycleTimeoutMs + ffiTeardownTimeoutMs + 2 s, which is 15 s at the nim-ffi defaults. A host that already calls logosdelivery_stop_node first sees no change, because the guard makes the destroy a no-op.

Dependency provenance: the v0.3.0 tag is an annotated tag on commit b6c17dc8. GitHub reports it as verified, and it carries the same signing key as the v0.3.0-rc.2 tag that master pins. The rc.2 to 0.3.0 delta adds no requires entry, so there is no new transitive dependency. The nimble and nix hashes were recomputed with a script that reproduces the checked-in rc.2 values byte for byte, and nimble itself resolves the package into nimbledeps/pkgs2/ffi-0.3.0-74e796df3ef39d828e014df701127edfbee459e0, which matches the nimble.lock checksum.

Validation: nim check passes on library/liblogosdelivery.nim and on the test, nimble dump accepts the new requirement, and nph is clean. The new e2e cases are not run yet, because they need the built shared library.

Issue

closes #4108

@github-actions

github-actions Bot commented Aug 7, 2026

Copy link
Copy Markdown

You can find the images built from this PR at

quay.io/wakuorg/nwaku-pr:4111
quay.io/wakuorg/nwaku-pr:4111-logosdeliverynode

Built from 5a3da84

@gmelodie
gmelodie requested review from Ivansete-status, NagyZoltanPeter and fcecin and removed request for NagyZoltanPeter and fcecin August 7, 2026 16:43
@gmelodie
gmelodie marked this pull request as ready for review August 7, 2026 16:43
@gmelodie
gmelodie force-pushed the chore/ffi/bump-rc3 branch from afad5bd to 019a5cc Compare August 7, 2026 16:43
Comment thread library/logos_delivery_api/node_api.nim Outdated

(await self.start()).isOkOr:
## A retry would stack a second set.
await self.dropFFIEventListeners()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dropFFIEventListeners nukes every event listener on the shared ctx using dropAllListeners, which includes the node's internal ones which are not re-registered when we retry failed starts or try a stop-then-start.

This PR is actually LGTM. It's just stepping on a pre-existing landmine/bug. I will fix the listener registration / lifetime bugs as my next task, if you want to wait for that before merging this PR (merging it as-is is also kind of fine because stop and restart is already broken and I'll have to fix it anyway, so this breaks it just a bit more in the unhappy path).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think any listener must be valid after successful start....
But I have concerns with the stop too, please not merge it yet.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@fcecin lmk when you're done! ty

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@fcecin lmk when you're done! ty

Done; Now we approve and merge #4118 into master, then merge master back here.

@gmelodie gmelodie changed the title feat(ffi): bump nim-ffi to 0.3.0-rc.3 and stop the node on destroy feat(ffi): pin nim-ffi 0.3.0 and stop the node on destroy Aug 10, 2026
@gmelodie
gmelodie requested a review from fcecin August 12, 2026 13:54
@gmelodie

Copy link
Copy Markdown
Collaborator Author

@fcecin @NagyZoltanPeter ready for reviewing!

@fcecin fcecin left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

FFI: logosdelivery_destroy without stop_node performs no node shutdown (recycle path leaves a live zombie node)

3 participants