Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

sqldb: InvoiceDB implementation #8052

Merged
merged 21 commits into from
Mar 7, 2024

Conversation

bhandras
Copy link
Collaborator

@bhandras bhandras commented Oct 2, 2023

This PR is based on the work of @positiveblue in #7357.
Also based on top of #8100 which is preliminary work refactoring the update invoice flow in order to be able to port InvoiceDB to SQL.

The PR is a collection of changes to the existing (but unreleased) schema and queries and implementation of a SQL based InvoiceDB utilizing the existing unit test coverage (moved from channeldb) and adding support for running the integration tests with native SQL invoice tables.

The PR does not implement migration for existing nodes!

To test locally, start a new regtest node with --db.backend=sqlite --db.use-native-sql flags.


This change is Reviewable

@bhandras
Copy link
Collaborator Author

Still a WIP draft, but now the SQL InvoiceStore works and so ready for some very early look.

@bhandras bhandras force-pushed the sql-invoices branch 3 times, most recently from b602bc0 to aca74ac Compare November 26, 2023 21:08
@bhandras bhandras force-pushed the sql-invoices branch 7 times, most recently from c4f1f5b to fb92a95 Compare December 6, 2023 19:03
@bhandras bhandras force-pushed the sql-invoices branch 3 times, most recently from 538e94e to 867ae27 Compare December 12, 2023 16:00
@bhandras bhandras marked this pull request as ready for review December 12, 2023 21:28
Copy link
Member

@Roasbeef Roasbeef left a comment

Choose a reason for hiding this comment

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

Amazing work! We're sooo close 🤩

The two main things that jumped out at me are:

  1. The shift (in this PR) of the relationship between an AMP invoice and an AMP payment. Before, we had a single AMP invoice, and then HTLCs are inserted that ref that invoice. Now, we have a single logical invoice, then several AMP invoices that point to that, and then several HTLCs for a given payment.

    The original model is closer to my personal mental model. Namely, an AMP invoice is identified by a payment_addr and any payments gain a new set_id value used ot ref them. At any given time, there's only one AMP invoice in the database.

  2. The shift away from the event sourced-esque model for the settle index. The original vision was that we wanted to break away from the settle index as is, as it's pretty brittle, and partially is what kept us from adding new indexes like a hold/add index.

    I think the event-sourced architecture is more flexible, and we can add additional fields to the events over time vs needing to modify the base invoice table. We'd have a root logical invoice_events table, then either a tiered approach where we ref a more specific event, like invoice_settles, or we'd have certain fields that are set based on the event type. One benefit of this, is that we can then replay ever event since they last check to the caller. This would include: adds, settles, cancel, etc. Today one would have to maintain an index for each event type, then ask for backlog for them all.

    With this approach, we can still give people just the settles, as the query filters on the event type and accumulates a counter along the way.

scripts/gen_sqlc_docker.sh Outdated Show resolved Hide resolved
sqldb/sqlc/migrations/000001_invoices.up.sql Show resolved Hide resolved
sqldb/sqlc/migrations/000001_invoices.up.sql Outdated Show resolved Hide resolved
sqldb/sqlc/migrations/000001_invoices.up.sql Show resolved Hide resolved
sqldb/sqlc/migrations/000001_invoices.up.sql Show resolved Hide resolved
config_builder.go Show resolved Hide resolved
config_builder.go Show resolved Hide resolved
sqldb/config.go Show resolved Hide resolved
sqldb/sqlerrors_js.go Outdated Show resolved Hide resolved
sqldb/sqlite_js.go Outdated Show resolved Hide resolved
bhandras added 20 commits March 1, 2024 10:08
This commit attempts to fix some issues with the invoice store's schema that we
couldn't foresee before the implementation was finished. This is safe as the
schema has not been instantiated yet outside of unit tests. Furthermore the
commit updates invoice store SQL queries according to fixes in the schema as
well as to prepare the higher level implementation in the upcoming commits.
Besides the usual unique constraint violation that we already support we
also want to return the same error if the primary key constraint is
violated.
This change will enable us to use a single PostgreSQL container instead of
spawning new a one for each (parallel) unit test reducing overall test
runtime.
This commit is part of a refactor that unifies configuration of the
sqldb and kvdb packages for SQL backends.
In order to unify the SQLite and Postgres configuration under sqldb we
first need to ensure that the final config types are compatible with
the alreay deployed versions.
This commit adds an optional separate "native" SQL backend that will
host all tables supporting native SQL. For now since we don't have many
such tables we'll keep it in one file for SQLite, but it may be split up
if desired.
Copy link
Collaborator Author

@bhandras bhandras left a comment

Choose a reason for hiding this comment

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

Dismissed @Roasbeef from a discussion.
Reviewable status: 43 of 44 files reviewed, 96 unresolved discussions (waiting on @positiveblue, @Roasbeef, @yyforyongyu, and @ziggie1984)


scripts/gen_sqlc_docker.sh line 19 at r2 (raw file):

Previously, Roasbeef (Olaoluwa Osuntokun) wrote…

Latest release is now v1.25.0: https://github.com/sqlc-dev/sqlc/releases/tag/v1.25.0

I think this'll be the last time we'll need to update it in this PR as they do a release every few months-ish.

done


sqldb/invoices.go line 1006 at r4 (raw file):

Previously, Roasbeef (Olaoluwa Osuntokun) wrote…

Set what state?

Yeah this was a leftover TODO comment for myself to check later, but it's irrelevant now, so removed.


sqldb/sqlc/migrations/000003_invoice_events.up.sql line 12 at r4 (raw file):

Previously, Roasbeef (Olaoluwa Osuntokun) wrote…

In most of the queries that involved inserting new event types, we currently use the integer ID here, so (this is for inserting a canceled event, but at a glance, you'd need to go to the initial table def to understand what 1 is):

INSERT INTO invoice_events (
    added_at, event_type, invoice_id
) VALUES (
    $1, 1, $2
);

I think we should consider instead using the description (and making that field UNIQUE), as then queries like the above are clearer as we'd have:

INSERT INTO invoice_events (
    added_at, event_type, invoice_id
) VALUES (
    $1, 'invoice_canceled', $2
);

The idea here was that we store the strings only once in the invoice_event_types tables and rather if need to have human readability we join the invoice_events table against it. This way if we have say 1m invoices and 2-3m events we wouldn't litter the db with strings unnecessarily.


sqldb/sqlc/queries/amp_invoices.sql line 5 at r4 (raw file):

Previously, Roasbeef (Olaoluwa Osuntokun) wrote…

Non-blocking, but it's also possbile to use the named params syntax here to make the queries a bit more readable: https://docs.sqlc.dev/en/latest/howto/named_parameters.html#naming-parameters

So this could be @set_id, @state, @created_at, @invoice_id, etc.

Yes that's a very good point and I was aware, but for now at least didn't really use the named notation because whenever we need to update a query it could lead to hard to catch bugs. An example of such bug would be if we have say multiple integer columns next to each other, and the order of the named arg is mixed up. It'd compile just fine and given many args reviewer may not spot it and depending on test coverage we may not catch it. By just adding numbered args we can always make sure that SQLC ensures the right order.

@bhandras
Copy link
Collaborator Author

bhandras commented Mar 1, 2024

Oh LGTM vanished once i answered in reviewable 😅 ptal @Roasbeef

Copy link
Member

@Roasbeef Roasbeef left a comment

Choose a reason for hiding this comment

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

re-LGTM 🏄🏻‍♀️

Copy link
Contributor

@positiveblue positiveblue left a comment

Choose a reason for hiding this comment

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

LGTM. I did yet another pass and found nothing seems to be blocking this PR @bhandras

The failing test in the test suite for windows is a flake not related with the code in this PR... I would say we are good to go 🚀

@saubyk saubyk removed the request for review from yyforyongyu March 7, 2024 01:33
@Roasbeef Roasbeef enabled auto-merge March 7, 2024 03:14
@Roasbeef Roasbeef disabled auto-merge March 7, 2024 03:15
@Roasbeef Roasbeef merged commit 716c6dd into lightningnetwork:master Mar 7, 2024
26 of 27 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
database Related to the database/storage of LND invoices sql
Projects
Status: Done
Development

Successfully merging this pull request may close these issues.

7 participants