-
Notifications
You must be signed in to change notification settings - Fork 2.2k
[Part 3|*] Implement Second Part for SQL Backend functions #10291
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
[Part 3|*] Implement Second Part for SQL Backend functions #10291
Conversation
80de0dd to
c0134ed
Compare
f0e3302 to
99ddf07
Compare
|
/gemini review |
There was a problem hiding this 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 implements a significant portion of the insert and delete methods for the new SQL backend for the payments database. The changes are extensive and include new SQL queries, data conversion functions, and the implementation of several methods on the SQLStore.
The use of ExecuteBatchQuery and ExecutePaginatedQuery is great for performance. The new PaymentAndIntent interface is a good abstraction.
I've found a few areas for improvement:
- Adherence to the function commenting style guide for exported functions.
- Consistent use of
context.Contextpropagation instead ofcontext.TODO(). - Opportunities for performance improvements by using batch inserts and optimizing queries to avoid extra fetches.
- A potential code smell related to handling of nil slices from the database.
Overall, this is a solid step forward in the SQL backend implementation. Addressing these points will improve the code's maintainability, robustness, and performance.
payments/db/sql_store.go
Outdated
| // TODO(ziggie): Can we get rid of this? | ||
| // This has to be in place otherwise the | ||
| // comparison will not match. | ||
| if record.Value == nil { | ||
| record.Value = []byte{} | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The TODO here highlights a potential code smell. This workaround of converting a nil slice to an empty slice might be hiding an issue or could be simplified. It would be beneficial to investigate whether the downstream code that consumes these records can be made to handle nil slices gracefully. This would remove the need for this conversion and make the data handling more consistent.
99ddf07 to
6145682
Compare
payments/db/sql_store.go
Outdated
| completePayment, err := s.fetchPaymentWithCompleteData( | ||
| ctx, db, fetchPayment, | ||
| ) | ||
| if err != nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i dont think we need to fetch the complete payment here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah looks like overkill to get all the data, I think we only need completePayment.Status?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
unfortunately we have to because it depends on the state of the HTLCs, so we need to always fetch the whole payment
se also func (m *MPPayment) setState() error {
yyforyongyu
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cool and would appreciate if the CIs can pass first before requesting reviews, especially the linter.
payments/db/sql_store.go
Outdated
| completePayment, err := s.fetchPaymentWithCompleteData( | ||
| ctx, db, fetchPayment, | ||
| ) | ||
| if err != nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah looks like overkill to get all the data, I think we only need completePayment.Status?
|
@ziggie1984, remember to re-request review from reviewers when ready |
6145682 to
047e180
Compare
047e180 to
5f2b14a
Compare
ziggie1984
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Addressed all the feedback, I think the batch inserting I will do in a followup PR.
payments/db/sql_store.go
Outdated
| completePayment, err := s.fetchPaymentWithCompleteData( | ||
| ctx, db, fetchPayment, | ||
| ) | ||
| if err != nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
unfortunately we have to because it depends on the state of the HTLCs, so we need to always fetch the whole payment
se also func (m *MPPayment) setState() error {
payments/db/sql_store.go
Outdated
| completePayment, err := s.fetchPaymentWithCompleteData( | ||
| ctx, db, existingPayment, | ||
| ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same as above we need to make sure no HTLCs are INFLIGHT and none exist or all are failed basically.
|
The itest for native_sql backends will not pass in this PR as well, they will start to pass from the next PR one (Part 4) |
8d382f4 to
9fd7eba
Compare
ellemouton
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
looking good!
payments/db/sql_store.go
Outdated
| return nil | ||
| } | ||
|
|
||
| ctx := context.TODO() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
keep at top of file?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: guess I don't understand this change - why moving this ctx definition?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am rebasing all these PRs on top of the complete serious and sometimes I think because later in the series these context get dropped and from some reason some merge conflict probably led to this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
payments/db/sql_store.go
Outdated
| // | ||
| // TODO(ziggie): Refactor to not mix application logic with database | ||
| // logic. This decision should be made in the application layer. | ||
| if s.keepFailedPaymentAttempts { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i think what YY is saying it that this is changing the behaviour as it currently stands. For KVStore: if DeletePayment is called from (r *rpcServer) DeletePayment, there is no check on keepFailedPaymentAttempts since it calls (p *KVStore) DeletePayment which does not check that. So if we want to keep the behaviour the same for (s *SQLStore) DeletePayment, then we should not check it there either.
| FirstHopCustomRecords | ||
|
|
||
| for key, value := range firstHopCustomRecords { | ||
| err = db.InsertPaymentFirstHopCustomRecord( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah i think there isnt right now an easy way to do bulk inserts
| CONSTRAINT idx_payments_payment_identifier_unique | ||
| UNIQUE (payment_identifier) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do we not want to instead name these?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think they are named and the name in this case is idx_payments_payment_identifier_unique , Can you confirm @gemini-code-assist
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, you are correct. The UNIQUE constraint is explicitly named idx_payments_payment_identifier_unique using the CONSTRAINT keyword. This is the standard way to provide a name for a constraint in SQL.
yyforyongyu
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Getting close!
| -- ───────────────────────────────────────────── | ||
|
|
||
| -- ───────────────────────────────────────────── | ||
| -- Payment Intents Table |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: for future commits, it'd be easier for the reviewers if we don't move the code yet add some changes in one commit, which can be challenging for the reviewers to do a line-by-line comparison.
payments/db/sql_store.go
Outdated
| return nil | ||
| } | ||
|
|
||
| ctx := context.TODO() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: guess I don't understand this change - why moving this ctx definition?
payments/db/sql_store.go
Outdated
| // | ||
| // TODO(ziggie): Refactor to not mix application logic with database | ||
| // logic. This decision should be made in the application layer. | ||
| if s.keepFailedPaymentAttempts { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah keepFailedPaymentAttempts is a config value, which means the users want to delete the failed attempts automatically after a payment is settled, this shouldn't affect how the DeletePayment works. However with the current change it will introduce a bug.
| return fmt.Errorf("failed to fetch payment: %w", err) | ||
| } | ||
|
|
||
| mpPayment, err = s.fetchPaymentWithCompleteData( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are there upcoming performance tests?
payments/db/sql_store.go
Outdated
|
|
||
| // Add the attempt to the payment without fetching it from the | ||
| // DB again. | ||
| mpPayment.HTLCs = append(mpPayment.HTLCs, HTLCAttempt{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Designing a safe DB layer is what we are trying to do here, yet we delegate that responsibility to the callers. The most proper way to handle this is via SELECT FOR UPDATE, but unfortunately due to our multi-sql schema support, this cannot be easily done at the moment. We sort of rely on the RegisterAttempt implemented in ControlTower, which holds a lock before calling this method, more like a mediation than solution. And here we already know this in-memory append will create a split brain issue with the data on disk, so I don't understand why we stick to this approach? @gemini-code-assist
If we are to go with this approach, we should document in details about the possible race, and how the mpPayment.HTLCs can be different from what's stored in db.
In this commit we add all queries which we will need to insert payment related data into the db.
9fd7eba to
dbcd822
Compare
ziggie1984
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you both for the thorough reviews 🙏
| CONSTRAINT idx_payments_payment_identifier_unique | ||
| UNIQUE (payment_identifier) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think they are named and the name in this case is idx_payments_payment_identifier_unique , Can you confirm @gemini-code-assist
payments/db/sql_store.go
Outdated
| return nil | ||
| } | ||
|
|
||
| ctx := context.TODO() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am rebasing all these PRs on top of the complete serious and sometimes I think because later in the series these context get dropped and from some reason some merge conflict probably led to this.
payments/db/sql_store.go
Outdated
| return nil | ||
| } | ||
|
|
||
| ctx := context.TODO() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
payments/db/sql_store.go
Outdated
| // | ||
| // TODO(ziggie): Refactor to not mix application logic with database | ||
| // logic. This decision should be made in the application layer. | ||
| if s.keepFailedPaymentAttempts { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
now I see it, weird that I had it in. Fixed. Nice catch!
| return fmt.Errorf("failed to fetch payment: %w", err) | ||
| } | ||
|
|
||
| mpPayment, err = s.fetchPaymentWithCompleteData( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes after migration we will focus on proper performance testing
payments/db/sql_store.go
Outdated
|
|
||
| // Add the attempt to the payment without fetching it from the | ||
| // DB again. | ||
| mpPayment.HTLCs = append(mpPayment.HTLCs, HTLCAttempt{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let's fetch the whole payment instead of doing the HTLC append in memory logic.
payments/db/sql_store.go
Outdated
|
|
||
| // Add the attempt to the payment without fetching it from the | ||
| // DB again. | ||
| mpPayment.HTLCs = append(mpPayment.HTLCs, HTLCAttempt{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nice catch and inputs 🙏
yyforyongyu
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM💟
payments/db/sql_store.go
Outdated
|
|
||
| // Insert blinded route data if present. Every hop in the | ||
| // blinded path must have an encrypted data record. | ||
| if hop.EncryptedData != nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
weird...I remembered this was changed before, but now changed back?
dbcd822 to
dc99a77
Compare
dc99a77 to
1101cc3
Compare
ellemouton
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
✅
a4756cd
into
lightningnetwork:elle-payment-sql-series-new
Depends on #10287
This PR implements most of the Insert and Delete methods we need for the unit tests in the following PR.