-
Notifications
You must be signed in to change notification settings - Fork 121
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
Spend transaction change outputs even if undelivered proof(s) #1074
Conversation
|
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.
Very nice!
tapdb/sqlc/queries/transfers.sql
Outdated
@@ -42,20 +42,25 @@ SET proof_delivery_complete = @delivery_complete | |||
WHERE output_id = (SELECT output_id FROM target); | |||
|
|||
-- name: QueryAssetTransfers :many | |||
SELECT | |||
id, height_hint, txns.txid, transfer_time_unix | |||
SELECT DISTINCT |
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.
Why is the distinct needed here? That's usually an indication that a JOIN isn't correct. Perhaps the asset_transfer_outputs
should not be a JOIN but rather be a sub query with a AND EXISTS(select 1 from asset_transfer_outputs ...)
?
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.
DISTINCT
is used because of the join on asset_transfer_outputs
. There are many other ways of accomplishing the same thing. Why should we disfavour DISTINCT
?
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'm just saying that whenever I see a DISTINCT
in a query, from experience, it's a sign that most likely something is fishy with the query. We're joining over an additional table, even though we don't need values from that table, so it should probably only be used in a sub-query (or maybe a CTE would fit here as well).
Also, I could imagine DISTINCT
not being super fast, but that's more of a gut feeling.
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.
Also, I think we should have a basic unit tests covering the new query. I myself made multiple mistakes in queries just because I didn't add proper unit tests.
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.
Thinking about this a bit more, perhaps in general we want both DISTINCT
and a better join? Here's my reasoning:
Without DISTINCT
we face two errors: duplicates and missing rows. But with DISTINCT
we only have to worry about missing rows. In other words, we do actually want the final rows to be DISTINCT
. And it might be good for robustness.
As for performance, I think we need to optimise against an actual problem, and I don't think we've seen a performance problem just yet. And it's not clear to me that performance is actually significantly affected.
But I also see your point that the rest of the query has to remove duplicates also. Otherwise we might lose precision in what we want the statement to achieve.
Do you think using DISTINCT
will hide problems though?
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 also don't understand what the DISTINCT
is doing here - how would we end up with duplicate or missing rows for this query?
The OR clause inside the AND also feels weird - I thought we have some other pattern to handle an optional filter like this that was more readable (but I couldn't find it with a cursory search).
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'm pretty sure we don't need the DISTINCT
anymore with the sub query. Before it was needed to de-duplicate because we selected/joined transfers and outputs but were only interested in fields of the transfers, so duplicates were possible.
But now we only select over transfers (and chain transactions, which should be a 1:1 relationship). So there shouldn't be any duplicates.
And I'm not sure what you mean by "missing rows"? Missing from what 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.
And I'm not sure what you mean by "missing rows"? Missing from what table?
I mean that one error type is that the query doesn't return some rows that should be there. And that DISTINCT
guarantees the absence of another error type: duplicate rows. It's nice to have that guarantee.
I agree that we don't need DISTINCT
but we might as well have it because it is what we want. We want the returned rows from the query to be distinct.
Anyway, I'm going to remove DISTINCT
for now because I don't think it matters very much. The JOIN has been modified as you suggested.
bc5cde5
to
5b211ff
Compare
Pull Request Test Coverage Report for Build 10373657954Details
💛 - Coveralls |
5b211ff
to
3dfecbe
Compare
3dfecbe
to
8338e95
Compare
This PR also adds extra useful fields to the |
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.
Looks generally good! Seems like the follow-up PR to assert that restart works should be pretty small.
Only outstanding Q is on the DB query changes.
2a40b27
to
fa4a66d
Compare
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.
Updates look good! Just blocking on that one unit test update.
This commit renames and generalizes the `unconf_only` argument in the `QueryAssetTransfers` SQL query to `pending_transfers_only`. The flag now returns pending transfers with unconfirmed anchoring transactions or undelivered transfer output proofs. Additionally, this update includes the anchor transaction block hash in the query's returned values. This allows users to determine if a transfer's anchoring transaction has been confirmed on-chain, providing context for why the transfer is pending. As a result of this change, ExportLog.PendingParcels will now also include transfers that are pending due to undelivered proofs, even if their associated anchoring transactions have already been confirmed on-chain.
This commit modifies the `ChainPorter` state machine to store the package state after the anchor transaction is confirmed, but before proof transfer is initiated. By ensuring the state is saved at this point, transfer change output coins remain spendable even if proof delivery fails.
This commit renames the ChainPorter state from SendStateStoreProofs to SendStateStorePostAnchorTxConf. The new name more accurately represents its function, reflecting that this state now performs broader storage updates beyond just storing proofs. Additionally, the name indicates that this state is triggered after the confirmation of the transfer anchoring transaction on-chain, without delving into the specific details of the operations performed within the state.
This commit renames the ExportLog method from ConfirmParcelDelivery to LogAnchorTxConfirm. The purpose of this change is to clarify that the method does not confirm parcel delivery to disk, as transfer proofs may still be pending. Instead, it updates the send package on disk to indicate that the transfer anchoring transaction has been confirmed on-chain.
This commit introduces the anchor transaction block hash as a field in the `AssetTransfer` RPC message. The `ListTransfers` RPC endpoint now includes this block hash for each asset transfer, provided the anchor transaction is confirmed. If the transaction is unconfirmed, this field will remain unset.
This commit enhances the ListTransfers RPC endpoint by adding the proof delivery status for each transfer output in its response.
This commit adds an itest which ensures that a tapd node is able to spend a change output even if the proof transfer for the previous transaction fails.
fa4a66d
to
6f0f23f
Compare
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 👍🏽
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.
Very nice, LGTM 🎉
One tiny request, but can also be deferred to follow-up PR, so non-blocking.
|
||
// The block hash the contains the anchor transaction above. If unset, the | ||
// anchor transaction is unconfirmed. | ||
bytes anchor_tx_block_hash = 7; |
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 request as here: #1075 (comment)
Whenever we reference block or transaction hashes, I think we should also return the human-readable (byte-reversed) variant that can be copy/pasted easily from the command line. So just add an additional anchor_tx_block_hash_str
that returns the .String()
variant.
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.
OK, I'll add this in a future PR (you mention in the review that you're ok with that). I think I've got a good pattern in mind.
Closes #1009
Refactor
ChainPorter
state machine such that change outputs can be spent even if proof delivery is incomplete.Changes
Integration Test: Spend Change on Failed Proof Delivery
Renaming Methods and States for Clarity
ConfirmParcelDelivery
method is renamed toLogAnchorTxConfirm
to more accurately reflect its functionality. This method now focuses on updating the send package on disk to indicate the anchoring transaction's on-chain confirmation, without "confirming parcel delivery" to disk (it never did that anyway).ChainPorter
state is renamed fromSendStateStoreProofs
toSendStateStorePostAnchorTxConf
. This new name better represents the broader storage updates performed after the anchor transaction confirmation, beyond just proof storage.State Management Enhancements
ChainPorter
state machine is updated to store the package state after the anchor transaction confirmation, but before initiating the proof transfer. This change ensures that the transfer change output coins remain spendable even if the proof delivery fails.Database Query Generalization
QueryAssetTransfers
SQL query argumentunconf_only
is generalized and renamed topending_transfers_only
. This updated flag now includes pending transfers with unconfirmed anchoring transactions or undelivered transfer output proofs. The query now also returns the anchor transaction block hash, allowing users to determine if the transfer's anchoring transaction has been confirmed on-chain.