Skip to content

cuprated: embeddable node library with Node::launch()#592

Merged
Boog900 merged 13 commits into
Cuprate:mainfrom
redsh4de:feat/embeddable-cuprate
May 18, 2026
Merged

cuprated: embeddable node library with Node::launch()#592
Boog900 merged 13 commits into
Cuprate:mainfrom
redsh4de:feat/embeddable-cuprate

Conversation

@redsh4de
Copy link
Copy Markdown
Contributor

@redsh4de redsh4de commented Mar 16, 2026

What

Extracts cuprated into an embeddable library (lib.rs/main.rs pattern). Takes inspiration from the API proposed in #554

Closes #516

Note to reviewers: This does not implement graceful shutdown / panic removal yet, those have been deferred to #585. For the final state with all changes, skip to #590

Why

To enable embedding the node in other applications

Where

cuprated:

  • Cargo.toml - explicit [lib] + [[bin]] targets
  • lib.rs (new) - Node struct, LaunchContext for initialization items, Node::launch()
  • main.rs - slimmed to a CLI wrapper over Node::launch()
  • config.rs - decoupled from CLI args; find_config() returns Result<Option<Config>>; dry_run_check() returns Vec<DryRunResult>
  • blockchain.rs - new BlockchainInterface composite handle
  • blockchain/syncer.rs - SyncNotify -> Syncer + SyncerHandle
  • blockchain/interface.rs - COMMAND_TX / BLOCKS_BEING_HANDLED statics -> BlockchainManagerHandle
  • signals.rs and statics.rs deleted; state lives in NodeContext for multi-instance use
  • version.rs - Default impl

consensus/fast-sync:

  • FAST_SYNC_HASHES static + set_fast_sync_hashes removed; fast_sync_stop_height and validate_entries take hashes as a parameter from LaunchContext

How

  1. Node::launch(config) initializes everything and returns the embedder API:
pub struct Node {
    pub blockchain: BlockchainInterface,
    pub txpool: TxpoolReadHandle,
    pub clearnet: NetworkInterface<ClearNet>,
    pub tor: Option<oneshot::Receiver<NetworkInterface<Tor>>>,
    pub syncer: SyncerHandle,
    pub config: Arc<Config>
}

Internal state previously held in mutable statics lives in LaunchContext - the node is now safe to run multiple times in a single process.

  1. The new BlockchainInterface composes three handles into one type for ergonomics:
pub struct BlockchainInterface {
    read: BlockchainReadHandle,
    context_svc: BlockchainContextService,
    manager: BlockchainManagerHandle,
}

Embedders use the public impl functions node.blockchain.read() and node.blockchain.context()

  1. The Tor interface arrives via oneshot after sync, similar to the dandelion.rs pattern.

@github-actions github-actions Bot added the A-binaries Area: Related to binaries. label Mar 16, 2026
@redsh4de redsh4de marked this pull request as draft March 16, 2026 16:38
@redsh4de redsh4de marked this pull request as ready for review March 16, 2026 17:45
@github-actions github-actions Bot added the A-dependency Area: Related to dependencies, or changes to a Cargo.{toml,lock} file. label Mar 17, 2026
@redsh4de redsh4de force-pushed the feat/embeddable-cuprate branch from c680c1c to 6542272 Compare March 17, 2026 12:59
@redsh4de redsh4de force-pushed the feat/embeddable-cuprate branch 2 times, most recently from 81d85e1 to 618b162 Compare March 18, 2026 03:38
@github-actions github-actions Bot added the A-consensus Area: Related to consensus. label Mar 18, 2026
Comment thread binaries/cuprated/src/lib.rs Outdated
Comment thread binaries/cuprated/src/lib.rs
Comment thread binaries/cuprated/src/lib.rs Outdated
Comment thread binaries/cuprated/src/lib.rs
@sneurlax
Copy link
Copy Markdown

you should try and return something like Result<Self, NodeInitError> rather than panicking

I don't get the difference between or relative purposes of Node and NodeContext. Which should be used for what?

with dry_run_check calling std::process::exit(code), won't an embedder calling config.dry_run_check() get their process killed?

nit but SyncState renamed unnecessarily imo

there's no way to shut it down?

I like main.rs after this tho. I like CommandHandle, get_fast_sync_hashes, BlockchainManagerHandle. not an in depth review but these things stood out to me in a once-over and some tangential reading to try and understand the changes

@redsh4de
Copy link
Copy Markdown
Contributor Author

redsh4de commented Mar 19, 2026

you should try and return something like Result<Self, NodeInitError> rather than panicking

Deferred this to the shutdown PRs - they depend on this branch so they carry everything over (https://github.com/Cuprate/cuprate/pull/585/changes#diff-d448bb1addb0153e0d62b48a7e6531f9988ea8f1846ab783540eaf9f2c87d87fR159)

I don't get the difference between or relative purposes of Node and NodeContext. Which should be used for what?

Node is meant to be the public facing API that the embedder receives and can interact with the node
NodeContext is meant to be the internal global context, replaces statics. Some things in each struct overlap but i prefer the granularity for the two seperate domains

Maybe there could be a better name for each struct so its self-documenting?

with dry_run_check calling std::process::exit(code), won't an embedder calling config.dry_run_check() get their process killed?

Yeah, good call

nit but SyncState renamed unnecessarily imo

It was a transitive change as i was also planning to add current sync target height to the struct, so the embedder can potentially create progress UIs/bars etc, got sidetracked though

there's no way to shut it down?

Ty, added shutdown function to #585 (https://github.com/Cuprate/cuprate/pull/585/changes#diff-d448bb1addb0153e0d62b48a7e6531f9988ea8f1846ab783540eaf9f2c87d87fR342-R344)

@sneurlax
Copy link
Copy Markdown

you should try and return something like Result<Self, NodeInitError> rather than panicking

Deferred this to the shutdown PRs - they depend on this branch so they carry everything over (https://github.com/Cuprate/cuprate/pull/585/changes#diff-d448bb1addb0153e0d62b48a7e6531f9988ea8f1846ab783540eaf9f2c87d87fR159)

I don't get the difference between or relative purposes of Node and NodeContext. Which should be used for what?

Node is meant to be the public facing API that the embedder receives and can interact with the node NodeContext is meant to be the internal global context, replaces statics. Some things in each struct overlap but i prefer the granularity for the two seperate domains

Maybe there could be a better name for each struct so its self-documenting?

with dry_run_check calling std::process::exit(code), won't an embedder calling config.dry_run_check() get their process killed?

Yeah, good call

nit but SyncState renamed unnecessarily imo

It was a transitive change as i was also planning to add current sync target height to the struct, so the embedder can potentially create progress UIs/bars etc, got sidetracked though

there's no way to shut it down?

Ty, added shutdown function to #585 (https://github.com/Cuprate/cuprate/pull/585/changes#diff-d448bb1addb0153e0d62b48a7e6531f9988ea8f1846ab783540eaf9f2c87d87fR342-R344)

Gotcha, OK :) sorry for the incomplete review then, glad to hear most of those issues are resolved by later PRs

Comment thread binaries/cuprated/src/commands.rs Outdated
Comment thread binaries/cuprated/src/config.rs
Comment thread binaries/cuprated/src/config.rs Outdated
Comment thread binaries/cuprated/src/blockchain/manager.rs Outdated
@SyntheticBird45
Copy link
Copy Markdown
Member

cancelling workflow because this is some doc nits, let's think a little about our carbon footprint.

@redsh4de
Copy link
Copy Markdown
Contributor Author

Think this is the last change i want to make here, didn't like how SyncNotify/State effectively functions as a handle without it being named such, reduces the mental load imo

Also added target_height to the handle so that embedders can create their own progress tracking items and whatnots

@redsh4de redsh4de force-pushed the feat/embeddable-cuprate branch 6 times, most recently from 6b7516e to 71b6dcc Compare April 26, 2026 19:53
@redsh4de redsh4de force-pushed the feat/embeddable-cuprate branch from 71b6dcc to 1caa5c5 Compare May 5, 2026 12:02
@redsh4de redsh4de force-pushed the feat/embeddable-cuprate branch from 1caa5c5 to 04a09db Compare May 12, 2026 15:58
@redsh4de redsh4de force-pushed the feat/embeddable-cuprate branch 2 times, most recently from 388a728 to 5336303 Compare May 14, 2026 00:11
@redsh4de redsh4de force-pushed the feat/embeddable-cuprate branch from 5336303 to f6797b6 Compare May 14, 2026 16:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-binaries Area: Related to binaries. A-consensus Area: Related to consensus. A-dependency Area: Related to dependencies, or changes to a Cargo.{toml,lock} file.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Make cuprate usable as a library

4 participants