Skip to content

Postgres follow-ups - #289

Open
tankyleo wants to merge 6 commits into
lightningdevkit:mainfrom
tankyleo:2026-09-postgres-e2e
Open

tankyleo wants to merge 6 commits into
lightningdevkit:mainfrom
tankyleo:2026-09-postgres-e2e

Conversation

@tankyleo

@tankyleo tankyleo commented Sep 19, 2026

Copy link
Copy Markdown
Contributor

Follow-ups to PR #243

Exercise a PostgreSQL-backed server between two SQLite-backed peers,
including direct and routed payments, process-kill recovery, persisted
wallet/channel/payment/forwarding state, and cooperative channel closure.

Cover force-close recovery across restart while funds are timelocked, then
confirm sweeps and reconcile wallet balances with confirmed onchain payment
records through the public APIs. Compare each node's pre-close onchain plus
Lightning balance with its settled onchain balance after cooperative and
force closes, allowing a 5,000-sat difference for fees. Verify final
balances and payment history survive another restart.

Verify two concurrent PostgreSQL-backed servers sharing a database use
separate configured tables and retain independent wallet balances and
payment histories across restart.

Add restart and PostgreSQL configuration support to the e2e harness.
Run the PostgreSQL tests explicitly in CI using postgres:latest, matching
LDK Node.

AI assistance: OpenAI Codex.
Explain that certificate_path is required to enable PostgreSQL TLS and
omitting it leaves sslmode=prefer connections unencrypted. Document the
sslmode=require failure without a CA file and the sslmode=disable conflict
when one is supplied in the configuration guide and example. Clarify the
CA requirement and plaintext default in CLI help.

AI assistance: OpenAI Codex.
@ldk-reviews-bot

ldk-reviews-bot commented Sep 19, 2026

Copy link
Copy Markdown

👋 Thanks for assigning @benthecarman 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.


services:
postgres:
image: postgres:latest
The test expected exactly one successful payment after sending the
Lightning payment. However, the successful-payment count also includes the
deposit and channel funding transaction. Depending on timing, the test could
pass because an onchain payment succeeded, or time out because the count
had already exceeded one.

Confirm both onchain payments and wait for their metrics before sending the
Lightning payment. Then require three successful payments with none pending
or failed, and include current metrics in the timeout diagnostic.

AI assistance: OpenAI Codex.
@benthecarman

Copy link
Copy Markdown
Collaborator

Can you add a description

@benthecarman benthecarman left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Thanks, didn't want to retest anything in ldk-node but these look reasonable.

some claude review

}
// Have SQLite discover the unilateral close onchain, ensuring PostgreSQL's commitment
// confirms without a competing commitment broadcast in response to a peer error message.
postgres

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

C can still reconnect to B during the force-close window. The force channel is inbound on C, so ldk-node re-adds B to C's peer store on ChannelPending. B's disconnect_peer only clears B's own store. If C's 60s reconnect tick lands before B's commitment confirms, B answers with an error and C force-closes with broadcast, producing a competing commitment. Low probability, but calling disconnect_peer from C's side as well removes the risk cheaply.

Comment thread e2e-tests/tests/postgres.rs Outdated
let server = LdkServerHandle::start_with_config(bitcoind, |params| {
// Each server gets its own table, even when sharing the same test database.
let table_name = format!(
"node_{}",

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

derives the table name by stripping a leading dot from the tempdir basename. That works only because tempfile uses a .tmp prefix and ldk-node splits identifiers on dots. format!("node_{}", params.grpc_port) is already unique and obviously valid.

}
}

async fn close_channel(initiator: &LdkServerHandle, peer: &LdkServerHandle, user_channel_id: &str) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

close_channel retries any LightningError for a full 60s in close_channel. That masks a real close failure as a generic timeout. Print the first error, or cap the retry to a few seconds.

Disconnect SQLite C from PostgreSQL B before force-closing, clearing the
peer stores on both sides. C stores B when the inbound channel becomes
pending, so disconnecting only B still allowed C to reconnect and
broadcast a competing commitment before B's commitment confirmed.

AI assistance: OpenAI Codex.
Use node_<grpc_port> for each test server's table name, removing the
dependency on tempfile basename formatting and leading-dot stripping.

AI assistance: OpenAI Codex.
Print the channel ID and full first close error in the PostgreSQL e2e
helper so retries do not obscure the original failure in test output.
Use a helper-local five-second timeout for the transient monitor-update
race so persistent close failures surface promptly.

AI assistance: OpenAI Codex.
@tankyleo

Copy link
Copy Markdown
Contributor Author

didn't want to retest anything in ldk-node but these look reasonable.

thanks yea tried to avoid too much duplication against ldk-node, seems a standalone e2e test in ldk-server could be useful to make sure we don't forget anything.

server
}

async fn channels(server: &LdkServerHandle, count: usize) -> Vec<Channel> {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

all the helpers in this file might be useful for other tests, can you see if there's any where we can use them and put them in the lib.rs instead of just this file

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