Skip to content

Conversation

@ziggie1984
Copy link
Collaborator

@ziggie1984 ziggie1984 commented Jan 8, 2026

Adds the KV db migration code to native SQL.

After merging this PR, the migration is still hidden behind test_native_sql

@ziggie1984 ziggie1984 self-assigned this Jan 8, 2026
@ziggie1984 ziggie1984 added migration sql payments Related to invoices/payments labels Jan 8, 2026
@gemini-code-assist
Copy link

Summary of Changes

Hello @ziggie1984, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request introduces a significant architectural change by migrating the payments database from a Key-Value (KV) store to a native SQL schema. The primary goal is to enhance database robustness, query flexibility, and overall performance for payment-related operations. It includes the complete implementation of the migration logic, a new SQL-backed payment store, and a comprehensive suite of tests to ensure data integrity and correct functionality during and after the migration. This change also prepares the system for future database optimizations and features by leveraging the capabilities of a relational database.

Highlights

  • KV-to-SQL Migration Logic: Introduced the core migration logic to transfer payment data from the existing Key-Value (KV) store to a new native SQL schema, including handling of historical duplicate payments by converting them into additional HTLC attempts.
  • New SQL Payment Store Implementation: Implemented a new SQL-backed payment store (SQLStore) that adheres to the existing payment database interfaces, providing methods for querying, fetching, initializing, registering, settling, failing, and deleting payments and their HTLC attempts.
  • Comprehensive Testing: Added extensive testing for the migration process, including basic happy-path tests, data integrity checks, property-based tests for various payment scenarios (MPP, AMP, custom records, blinded routes), and a helper for debugging with external database files.
  • Database Schema Integration: Integrated the new payment migration into the main database build process by adding a new paymentMigration constant and a custom migration function in config_builder.go, along with a mechanism to prevent reopening the old KV payments bucket after migration.
  • Payment Data Structures and Utilities: Defined new Go data structures for payments, HTLC attempts, and their statuses (MPPayment, HTLCAttempt, PaymentStatus), along with serialization/deserialization codecs and error types specific to the migration and new SQL store.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@ziggie1984 ziggie1984 added this to v0.21 Jan 8, 2026
@ziggie1984 ziggie1984 added this to the v0.21.0 milestone Jan 8, 2026
Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a comprehensive migration for the payments database from a key-value store to SQL. The changes are well-structured, with the migration logic encapsulated in a new payments/db/migration1 package. This package includes a reader for the old KV store format, cleverly handling historical data quirks like duplicate payments by migrating them as HTLC attempts on the primary payment. The migration is correctly wired into the application startup, guarded by a new migration version and a tombstone mechanism to prevent accidental use of the old database post-migration. The testing strategy is particularly strong, featuring data integrity checks, property-based tests, and specific tests for various payment features, which provides high confidence in the correctness of this complex change. My review is positive, with only a couple of minor stylistic suggestions to improve readability.

Comment on lines +1168 to +1174
return fmt.Errorf("failed to migrate "+
"payments to SQL: %w", err)

Choose a reason for hiding this comment

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

medium

This string concatenation is not necessary as the resulting line is well within the 80-character limit. Combining it into a single string improves readability and adheres to the style guide's principle of minimizing lines for error messages where possible.

This applies to a few other places in this file as well:

  • Line 1175: d.logger.Debugf("Setting payments bucket tombstone")
  • Line 1308: err = fmt.Errorf("unable to check payments bucket tombstone: %w", err)
  • Line 1315: err = fmt.Errorf("payments bucket tombstoned, please switch back to native SQL")
return fmt.Errorf("failed to migrate payments to SQL: %w", err)
References
  1. The style guide states to 'Minimize lines for log and error messages, while adhering to the 80-character limit.' The current code unnecessarily splits a short line, which goes against the 'minimize lines' principle. (link)

Comment on lines +232 to +233
return fmt.Errorf("non bucket element" +
"in duplicate bucket")

Choose a reason for hiding this comment

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

medium

This string concatenation is unnecessary and can be combined into a single string to improve readability and adhere to the style guide's principle of minimizing lines for error messages.

return fmt.Errorf("non bucket element in duplicate bucket")
References
  1. The style guide states to 'Minimize lines for log and error messages, while adhering to the 80-character limit.' The current code unnecessarily splits a short line, which goes against the 'minimize lines' principle. (link)

@ziggie1984 ziggie1984 force-pushed the elle-payment-sql-series-new branch from d8531d2 to 2930b37 Compare January 8, 2026 12:56
@ziggie1984 ziggie1984 force-pushed the migration-kvdb-sql-payments-part1 branch 2 times, most recently from 2802da4 to 83bce46 Compare January 8, 2026 12:59
@saubyk saubyk moved this to In progress in v0.21 Jan 8, 2026
@ziggie1984 ziggie1984 force-pushed the elle-payment-sql-series-new branch from 2930b37 to 8c106c7 Compare January 8, 2026 15:43
Add a migration specific query which allows to set the failure
reason when inserting a payment into the db.
Older LND versions could create multiple payments for the same hash.
We need to preserve those historical records during KV→SQL migration,
but they don’t fit the normal payment schema because we enforce a
unique payment hash constraint. Introduce a lean payment_duplicates
table to store only the essential fields (identifier, amount,
timestamps, settle/fail data).

This keeps the primary payment records stable and makes the migration
deterministic even when duplicate records lack attempt info. The table
is intentionally minimal and can be dropped after migration if no
duplicate payments exist.

For now there is no logic in place which allows the noderunner to
fetch duplicate payments after the migration.
@ziggie1984 ziggie1984 force-pushed the migration-kvdb-sql-payments-part1 branch from 622021b to fc449ad Compare January 10, 2026 23:12
@ziggie1984
Copy link
Collaborator Author

/gemini review

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces the migration logic for moving payment data from the key-value store to a SQL database. The changes are extensive, including a new payments/db/migration1 package that encapsulates the migration logic, new SQL schema definitions for duplicate payments, and the necessary wiring in the configuration builder to trigger the migration. The approach is solid, with good isolation of migration code and thorough validation checks to ensure data integrity. I've found a few minor issues related to code style and typos in error messages and comments, which I've detailed in the review comments.

Comment on lines +1163 to +1171
var err error
err = paymentsmig1.MigratePaymentsKVToSQL(
ctx,
dbs.ChanStateDB.Backend,
paymentsmig1sqlc.New(tx.GetTx()),
&paymentsmig1.SQLStoreConfig{
QueryCfg: queryCfg,
},
)

Choose a reason for hiding this comment

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

medium

The declaration of err on line 1163 is redundant. You can use a short variable declaration := on line 1164 to declare and initialize err in one step, which is more idiomatic Go.

                                err := paymentsmig1.MigratePaymentsKVToSQL(
					ctx,
					dbs.ChanStateDB.Backend,
					paymentsmig1sqlc.New(tx.GetTx()),
					&paymentsmig1.SQLStoreConfig{
						QueryCfg: queryCfg,
					},
				)

Comment on lines +28 to +29
return fmt.Errorf("payments bucket does not "+
"exist: %w", err)

Choose a reason for hiding this comment

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

medium

The error message "payments bucket does not exist" is confusing here, as this code block is executed when attempting to create the bucket. A more accurate message would be "failed to create payments bucket".

Suggested change
return fmt.Errorf("payments bucket does not "+
"exist: %w", err)
return fmt.Errorf("failed to create payments "+
"bucket: %w", err)

Comment on lines +232 to +233
return fmt.Errorf("non bucket element" +
"in duplicate bucket")

Choose a reason for hiding this comment

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

medium

There's a typo in the error message. A space is missing between "element" and "in", which would result in "non bucket elementin duplicate bucket".

Suggested change
return fmt.Errorf("non bucket element" +
"in duplicate bucket")
return fmt.Errorf("non bucket element " +
"in duplicate bucket")

err = dup.ForEach(func(k, v []byte) error {
subBucket := dup.NestedReadBucket(k)
if subBucket == nil {
// We one bucket for each duplicate to be found.

Choose a reason for hiding this comment

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

medium

There's a typo in this comment. It should probably say "We expect one bucket..." to be grammatically correct.

Suggested change
// We one bucket for each duplicate to be found.
// We expect one bucket for each duplicate to be found.

Comment on lines +2108 to +2109
log.Warnf("Failed to decode extra TLV bytes for "+
"failure message: %v", err)

Choose a reason for hiding this comment

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

medium

There's a typo in the log message. A space is missing between "for" and "failure", which would result in "forfailure message".

Suggested change
log.Warnf("Failed to decode extra TLV bytes for "+
"failure message: %v", err)
log.Warnf("Failed to decode extra TLV bytes for "+
"failure message: %v", err)

Copy the core payments/db helpers into payments/db/migration1 and add the required sqlc-generated types/queries from sqldb/sqlc. This effectively freezes the migration code so it stays robust against future query or schema changes in the main payments package.
Implement the KV→SQL payment migration and add an in-migration validation pass that deep-compares KV and SQL payment data in batches. Duplicate payments are migrated into the payment_duplicates table, and duplicates without attempt info or explicit resolution are marked failed to ensure terminal state. Validation checks those rows as well.
Add test helpers plus sql_migration_test coverage for KV→SQL migration: basic migration, sequence ordering, data integrity, and feature-specific cases (MPP/AMP, custom records, blinded routes, metadata, failure messages). Also cover duplicate payment migration to payment_duplicates, including missing attempt info to ensure terminal failure is recorded.

This gives broad regression coverage for the migration path and its edge-cases.
Add a developer-facing migration_external_test that allows running the KV→SQL payments migration against a real channel.db/channel.sqlite (or a KV postgres backend) to debug migration failures on actual data. The accompanying testdata README documents how to supply a database file and configure the test, so users can validate their data and confirm the migration completes successfully.

The test is skipped by default and meant for manual diagnostics.
Hook the payments KV→SQL migration into the SQL migration config and config builder, add logging for the migration path, and introduce tombstone protection to prevent re-running once migration completes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

migration payments Related to invoices/payments sql

Projects

Status: In progress

Development

Successfully merging this pull request may close these issues.

1 participant