Skip to content

Expose Postgres storage backend - #243

Open
benthecarman wants to merge 1 commit into
lightningdevkit:mainfrom
benthecarman:postgres
Open

Expose Postgres storage backend#243
benthecarman wants to merge 1 commit into
lightningdevkit:mainfrom
benthecarman:postgres

Conversation

@benthecarman

Copy link
Copy Markdown
Collaborator

Allow ldk-server to configure LDK Node wallet and channel state storage through PostgreSQL without a feature-gated server build. Keep local disk storage for server-owned files and history, and document the backup boundary.

@ldk-reviews-bot

ldk-reviews-bot commented Jul 7, 2026

Copy link
Copy Markdown

👋 Thanks for assigning @tankyleo as a reviewer!
I'll wait for their review and will help manage the review process.
Once they submit their review, I'll check if a second reviewer would be helpful.

@benthecarman
benthecarman force-pushed the postgres branch 2 times, most recently from c79c1a4 to a4378ea Compare July 12, 2026 19:41
@benthecarman
benthecarman requested review from tankyleo and removed request for valentinewallace July 28, 2026 00:44

@tankyleo tankyleo 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.

skimmed briefly one question

Comment thread docs/configuration.md

When `[storage.postgres]` is configured, LDK Node wallet/channel state is stored in
PostgreSQL instead of `ldk_node_data.sqlite`. The storage directory remains required for
the mnemonic, API key, TLS material, logs, and `ldk_server_data.sqlite`.

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.

Would big routing nodes want ldk_server_data.sqlite to be in the postgres db too, given that they'll be forwarding a lot of payments ? Or is that for a later PR / out-of-scope here ?

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.

It will be after lightningdevkit/ldk-node#772, just keeping the docs accurate of the local state of the repo. Will update once we merge and upgrade here

@tankyleo
tankyleo self-requested a review July 28, 2026 02:58

# Optional LDK Node PostgreSQL storage for wallet and channel state.
#[storage.postgres]
#connection_string = "postgresql://postgres:postgres@localhost:5432" # PostgreSQL connection string. Do not include dbname if db_name is set.

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.

If it works I find the key value format to be cleaner, less error prone ie host=localhost port=5432 user=postgres sslmode=disable

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.

tbh i always hate these, but can switch if we really want

Comment thread docs/configuration.md
```

Only `connection_string` is required. `db_name`, `kv_table_name`, and `certificate_path`
are optional. If `db_name` is set, do not also include a database name in the connection

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.

Don't remember us explicitly rejecting a database name in the connection string anywhere in this patch ? Would it be good to add test coverage for this?

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.

that's in ldk-node, added a test for this

Comment thread docs/configuration.md

```toml
[storage.postgres]
connection_string = "postgresql://postgres:postgres@localhost:5432"

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.

Similar here, the key-value format would be better if we can have it.

Comment thread ldk-server/src/util/config.rs Outdated
|| args.storage_postgres_kv_table_name.is_some()
|| args.storage_postgres_certificate_path.is_some()
{
let mut postgres = self.ldk_node_postgres.take().unwrap_or_default();

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.

Here we can do a get_or_insert_default, so we don't need the assignment at the end of the block.

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.

done

Comment thread ldk-server/src/util/config.rs Outdated

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.

Similar here can do a get_or_insert_default if you care to :)

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.

done

LdkNodeStorageConfig::Postgres {
connection_string: postgres
.connection_string
.ok_or_else(|| missing_field_err("storage_postgres_connection_string"))?,

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.

For this field I wonder if this is a sensible default:
host=localhost port=5432 user=postgres sslmode=disable

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.

Imo probably better to not have a defualt connection string

Allow ldk-server to configure LDK Node wallet and channel state
storage through PostgreSQL without a feature-gated server build. Keep
local disk storage for server-owned files and history, and document the
backup boundary.

AI-assisted-by: OpenAI Codex
@joostjager

Copy link
Copy Markdown
Contributor

Posting some AI comments that look sensible. Second one is in flight in lightningdevkit/ldk-node#1000, but maybe it should be a prerequisite.

🤖 Requesting changes for two fund-safety blockers.

  1. The backend is selected only after reusing the existing mnemonic, with no migration or continuity check. Adding [storage.postgres] to an existing SQLite deployment therefore preserves the same Lightning identity while an empty PostgreSQL target creates fresh wallet and channel-manager state and silently ignores ldk_node_data.sqlite. For a node with live channels, starting without its channel monitors can lose channel funds. Please require an explicit verified migration, persist and validate backend identity, or at minimum refuse this switch when local SQLite LDK state exists and the PostgreSQL destination is empty.

  2. The PostgreSQL build path does not acquire exclusive ownership of the database and table. Two deployments with the same mnemonic and target can both pass descriptor and network validation, read the same snapshot, and start the same node identity. The pinned PostgreSQL store uses process-local ordering locks and unconditional upserts, so overlapping instances can interleave stale channel-manager and monitor writes. Please hold a database advisory lock or equivalent lease for the node lifetime and fail the second writer before building the node.

The previous cross-network concern is fail-closed in the pinned dependency because the persisted BDK network is checked during wallet load. The target is still not network-isolated, however, so the operations claim that multiple networks can share one storage root without conflicts should state that PostgreSQL deployments need distinct database or table targets per network.

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.

4 participants