-
Notifications
You must be signed in to change notification settings - Fork 145
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
fix(api): idempotency bug in registerBroadcastHandler #3558
Conversation
d2cdb7b
to
28279fe
Compare
export const isOnChainFeeReconciliationTxn = ( | ||
txn: LedgerTransaction<WalletCurrency>, | ||
): boolean => | ||
txn.type === LedgerTransactionType.OnchainPayment && txn.address === undefined |
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.
not sure when we began to use non undefinied/null/empty validation (should be !txn.address
we already had an issue in prod with this) also.. should not include bankowner wallet id validation?
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.
In this case I was thinking it should specifically check for the absence of the address
property (since the OnChainAddress
can technically also be falsy/empty even though it should never be). Or, what sort of issue has this thrown in prod?
should not include bankowner wallet id validation
Maybe not necessary since the reconciliation transaction only ever involves Liabilities:bankOwner
account and Asset:OnChain
accounts and I believe we only bring in Liabilities
accounts in our ledger get
methods. address
absence should be enough for this check?
Sidenotes:
For this check, ideally it should be a different tx type
value instead of also being an onchain_payment
so we don't even need the check, but that might be a tricky migration to do. And I also considered maybe setting a custom description for these types of transactions but then there was no way to guarantee that someone couldn't set the same description on normal onchain-payment transactions which would break the heuristic. I switched from checking for satsFee
presence to address
presence since this is more isolated and might less likely eventually be populated on the reconciliation-type transactions that get constructed inside FeeOnlyEntryBuilder
.
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.
at least with validations in data from external services we must be more "defensive", we cant guarantee the undefined so it is safer just to use !txn.address
FYI: the error was a validation using undefined and a service returning null value (typescript in theory was ok but you know we cant trust TS )
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.
Oh yea ok that makes sense.
For here though, address
is set explicitly in our translateToLedgerTx
function, so there's also less risk of it being something unexpected? We handle the uncertain-falsy-check-from-external-service in the line tx.payee_addresses && tx.payee_addresses.length > 0
inside translateToLedgerTx
@@ -168,7 +169,7 @@ export const setOnChainTxIdByPayoutId = async ({ | |||
|
|||
const bankOwnerWalletId = await getBankOwnerWalletId() | |||
const bankOwnerTxns = txns.filter( | |||
(txn) => txn.satsFee && txn.walletId === bankOwnerWalletId, | |||
(txn) => !isOnChainFeeReconciliationTxn(txn) && txn.walletId === bankOwnerWalletId, |
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.
can reconciliation be applied to other wallets (different from bankowner)?
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.
Mm, it shouldn't be since reconciliations only involve Liabilities:bankOwner
and Assets:OnChain
. Why do you ask?
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.
if that is the case then walletId validation should be in isOnChainFeeReconciliationTxn
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.
Not sure if that would be helpful here though, because we'd still need to do the txn.walletId === bankOwnerWalletId
check since normal non-reconciliation onchain_payment
txns can also be from user wallet ids
I switched the check order around to this to try to make this check more intuitive:
(txn) => txn.walletId === bankOwnerWalletId && !isOnChainFeeReconciliationTxn(txn),
28279fe
to
810778c
Compare
This is to fix the idempotency bug introduced in: #3550
810778c
to
df0a32a
Compare
Description
In PR #3550, by fixing the idempotency issue where an
InvalidLedgerTransactionStateError
is thrown if the handler is re-run and records a reconciliation transaction (see traces), we introduced a new bug where multiple reconciliation transaction are created on re-run.This PR cleans up the fix from #3550 by introducing an explicit
isOnChainFeeReconciliationTxn
check and it fixes the new multiple-reconciliation-txns bug.