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

Funding transactions created in quick succession attempt to spend the same output #477

Open
MaxFangX opened this issue Feb 26, 2025 · 3 comments

Comments

@MaxFangX
Copy link
Contributor

Hiya, I've noticed an odd behavior in our logs during JIT channel opens. When JIT channel opens are triggered in quick succession, multiple funding transactions are broadcast that try to spend the same outpoint. Naturally, only the first broadcast succeeds, and subsequent ones are rejected by the mempool. I looked over to ldk-node to see how it handles FundingGenerationReady and ldk-node has almost the exact same behavior as us, so I figured ldk-node probably has this problem too. It seems likely that this problem may even apply to BDK sends in general. At this point I'm not sure if this should be fixed on the BDK side or via external tracking or syncing in LDK node; just wanted to start a discussion.

Here are some sample test logs from us. Note how the last three groups of logs (each corresponding to a JIT channel open) all attempt to spend the same txout f7a25f4f4eee9ee1da0972076bfbf83e61b2ca589e4e591abb9e070e868d1129:0, with only the first broadcast succeeding.

  • (LSP starts with 50 BTC block subsidy)
  • LSP sends 1 BTC to User 0
  • User 0 opens 200k sat channel to LSP
  • User 0 makes 100k sat payment to user 1, triggering LSP JIT channel to user 1 with value 150k sats
  • User 1 makes 10k sat payment to user 2, triggering LSP JIT channel to user 2 with value 60k sats
  • User 1 makes 80k sat payment to user 2, triggering LSP JIT channel to user 2 with value 180k sats
2025-02-26T02:27:27.069221Z  INFO (lsp):(lexe-lsp-run-server):(req)(srv):(pay-onchain):(esplora-broadcast):(broadcast-txs-inner): lexe_ln::esplora: Broadcasting batch of 1 txs user_pk=a9edf959 trace_id=xS1zGgecYCZeSv8w from=lexe method=POST url=/lexe/pay_onchain version=HTTP/2.0
2025-02-26T02:27:27.074055Z  INFO (lsp):(lexe-lsp-run-server):(req)(srv):(pay-onchain):(esplora-broadcast):(broadcast-txs-inner):(req)(cli): lxapi: Done (success) req_time=4.686ms status=200 user_pk=a9edf959 trace_id=xS1zGgecYCZeSv8w from=lexe method=POST url=/lexe/pay_onchain version=HTTP/2.0 from=lsp to=backend method=PUT url=https://localhost:61146/lsp/events attempts_left=1
2025-02-26T02:27:27.074155Z  INFO (lsp):(lexe-lsp-run-server):(req)(srv):(pay-onchain):(esplora-broadcast):(broadcast-txs-inner): lexe_ln::esplora: Broadcasting transaction: txid=f7a25f4f4eee9ee1da0972076bfbf83e61b2ca589e4e591abb9e070e868d1129, num_inputs=1, num_outputs=2, inputs=[7f5ab849726f4a9731db7c9d749b7b583614dc103235be900eba07b62dafe26f:0], outputs=[(4899999859 SAT, Script(OP_0 OP_PUSHBYTES_20 e9b5d528a166dd3dde3eacc6f4a7b3887e80b14a)), (100000000 SAT, Script(OP_0 OP_PUSHBYTES_20 7937d602f903a965d8b6d7eb1ece3395f04d9ed7))] user_pk=a9edf959 trace_id=xS1zGgecYCZeSv8w from=lexe method=POST url=/lexe/pay_onchain version=HTTP/2.0
2025-02-26T02:27:27.077812Z DEBUG (lsp):(lexe-lsp-run-server):(req)(srv):(pay-onchain):(esplora-broadcast):(broadcast-txs-inner): lexe_ln::esplora: Broadcasted tx f7a25f4f4eee9ee1da0972076bfbf83e61b2ca589e4e591abb9e070e868d1129 user_pk=a9edf959 trace_id=xS1zGgecYCZeSv8w from=lexe method=POST url=/lexe/pay_onchain version=HTTP/2.0
2025-02-26T02:27:27.077859Z DEBUG (lsp):(lexe-lsp-run-server):(req)(srv):(pay-onchain):(esplora-broadcast):(broadcast-txs-inner): lexe_ln::test_event: (lsp) sending test event: TxBroadcasted user_pk=a9edf959 trace_id=xS1zGgecYCZeSv8w from=lexe method=POST url=/lexe/pay_onchain version=HTTP/2.0
2025-02-26T02:27:27.077879Z  INFO (lsp):(lexe-lsp-run-server):(req)(srv):(pay-onchain):(esplora-broadcast):(broadcast-txs-inner): lexe_ln::esplora: Batch broadcast of 1 txs succeeded user_pk=a9edf959 trace_id=xS1zGgecYCZeSv8w from=lexe method=POST url=/lexe/pay_onchain version=HTTP/2.0
2025-02-26T02:27:28.165693Z  INFO (node):(bgp):(event-handler)(chan-man):(broadcaster-interface):(broadcast-txs-inner): lexe_ln::esplora: Broadcasting batch of 1 txs user_pk=bbf6c8a9
2025-02-26T02:27:28.165739Z  INFO (node):(bgp):(event-handler)(chan-man):(broadcaster-interface):(broadcast-txs-inner): lexe_ln::esplora: Broadcasting transaction: txid=166b3031039ebc48ba283b5400717fc6a9f2279113505a7980c36000abe7d80b, num_inputs=1, num_outputs=2, inputs=[f7a25f4f4eee9ee1da0972076bfbf83e61b2ca589e4e591abb9e070e868d1129:1], outputs=[(99799847 SAT, Script(OP_0 OP_PUSHBYTES_20 9ab2f97db3293413959622a8b44b54b83b67814e)), (200000 SAT, Script(OP_0 OP_PUSHBYTES_32 852078d54f0127183f2622162671212835b2a0cff054f1e0054ad2dfc3a219a2))] user_pk=bbf6c8a9

2025-02-26T02:27:28.166578Z DEBUG (node): common::task: Received ephemeral task: (broadcaster-interface) user_pk=bbf6c8a9
2025-02-26T02:27:28.168656Z DEBUG (node):(bgp):(event-handler)(chan-man):(broadcaster-interface):(broadcast-txs-inner): lexe_ln::esplora: Broadcasted tx 166b3031039ebc48ba283b5400717fc6a9f2279113505a7980c36000abe7d80b user_pk=bbf6c8a9
2025-02-26T02:27:28.168699Z DEBUG (node):(bgp):(event-handler)(chan-man):(broadcaster-interface):(broadcast-txs-inner): lexe_ln::test_event: (node) sending test event: TxBroadcasted user_pk=bbf6c8a9
2025-02-26T02:27:28.168716Z  INFO (node):(bgp):(event-handler)(chan-man):(broadcaster-interface):(broadcast-txs-inner): lexe_ln::esplora: Batch broadcast of 1 txs succeeded user_pk=bbf6c8a9
2025-02-26T02:27:28.168736Z DEBUG (node):(bgp):(event-handler)(chan-man):(broadcaster-interface): lexe_ln::esplora: Broadcasted txs successfully user_pk=bbf6c8a9
2025-02-26T02:27:28.168787Z  INFO (node): common::task: Task '(broadcaster-interface)' finished user_pk=bbf6c8a9
2025-02-26T02:27:28.168806Z DEBUG (node): common::task: Ephemeral task finished: (broadcaster-interface) user_pk=bbf6c8a9

2025-02-26T02:27:29.533654Z DEBUG (lsp): common::task: Received ephemeral task: (broadcaster-interface) user_pk=a9edf959
2025-02-26T02:27:29.533701Z  INFO (lsp):(bgp):(event-handler)(chan-man):(broadcaster-interface):(broadcast-txs-inner): lexe_ln::esplora: Broadcasting batch of 1 txs user_pk=a9edf959
2025-02-26T02:27:29.540549Z  INFO (lsp):(bgp):(event-handler)(chan-man):(broadcaster-interface):(broadcast-txs-inner):(req)(cli): lxapi: Done (success) req_time=6.715ms status=200 user_pk=a9edf959 from=lsp to=backend method=PUT url=https://localhost:61146/lsp/events trace_id="RC7YV7JtfGnFeAmk" attempts_left=1
2025-02-26T02:27:29.540636Z  INFO (lsp):(bgp):(event-handler)(chan-man):(broadcaster-interface):(broadcast-txs-inner): lexe_ln::esplora: Broadcasting transaction: txid=b78aaf03c008033d9d9aaeb795e4d42642b327c04230717cf04bb3731cb4f8b3, num_inputs=1, num_outputs=2, inputs=[f7a25f4f4eee9ee1da0972076bfbf83e61b2ca589e4e591abb9e070e868d1129:0], outputs=[(150000 SAT, Script(OP_0 OP_PUSHBYTES_32 41e897dcf18e1687a96127f0d24d408283a0a732bdefaf79cdf7cf6d2c796120)), (4899849706 SAT, Script(OP_0 OP_PUSHBYTES_20 c211f47c59ceb3a3913a2d544439f226f2c786bb))] user_pk=a9edf959
2025-02-26T02:27:29.544313Z DEBUG (lsp):(bgp):(event-handler)(chan-man):(broadcaster-interface):(broadcast-txs-inner): lexe_ln::esplora: Broadcasted tx b78aaf03c008033d9d9aaeb795e4d42642b327c04230717cf04bb3731cb4f8b3 user_pk=a9edf959
2025-02-26T02:27:29.544427Z DEBUG (lsp):(bgp):(event-handler)(chan-man):(broadcaster-interface):(broadcast-txs-inner): lexe_ln::test_event: (lsp) sending test event: TxBroadcasted user_pk=a9edf959
2025-02-26T02:27:29.544447Z  INFO (lsp):(bgp):(event-handler)(chan-man):(broadcaster-interface):(broadcast-txs-inner): lexe_ln::esplora: Batch broadcast of 1 txs succeeded user_pk=a9edf959
2025-02-26T02:27:29.544474Z DEBUG (lsp):(bgp):(event-handler)(chan-man):(broadcaster-interface): lexe_ln::esplora: Broadcasted txs successfully user_pk=a9edf959
2025-02-26T02:27:29.544545Z  INFO (lsp): common::task: Task '(broadcaster-interface)' finished user_pk=a9edf959
2025-02-26T02:27:29.544581Z DEBUG (lsp): common::task: Ephemeral task finished: (broadcaster-interface) user_pk=a9edf959

2025-02-26T02:27:35.189936Z DEBUG (lsp): common::task: Received ephemeral task: (broadcaster-interface) user_pk=a9edf959
2025-02-26T02:27:35.190027Z  INFO (lsp):(bgp):(event-handler)(chan-man):(broadcaster-interface):(broadcast-txs-inner): lexe_ln::esplora: Broadcasting batch of 1 txs user_pk=a9edf959
2025-02-26T02:27:35.196299Z  INFO (lsp):(bgp):(event-handler)(chan-man):(broadcaster-interface):(broadcast-txs-inner):(req)(cli): lxapi: Done (success) req_time=6.095ms status=200 user_pk=a9edf959 from=lsp to=backend method=PUT url=https://localhost:61146/lsp/events trace_id="WQbdFeT3bt6wItoi" attempts_left=1
2025-02-26T02:27:35.196409Z  INFO (lsp):(bgp):(event-handler)(chan-man):(broadcaster-interface):(broadcast-txs-inner): lexe_ln::esplora: Broadcasting transaction: txid=eb6451e9a7de40de78138dc3615c4261c38cad6947e95bcb6a8c8557dfeb93ba, num_inputs=1, num_outputs=2, inputs=[f7a25f4f4eee9ee1da0972076bfbf83e61b2ca589e4e591abb9e070e868d1129:0], outputs=[(4899939706 SAT, Script(OP_0 OP_PUSHBYTES_20 f3fa194cad5a39bf5c1a715fa0d261abc40648b5)), (60000 SAT, Script(OP_0 OP_PUSHBYTES_32 7a761d9a803aea29e02fac5f64039ae398460e62349dbd92798f52066923bc49))] user_pk=a9edf959
2025-02-26T02:27:35.199994Z ERROR (lsp):(bgp):(event-handler)(chan-man):(broadcaster-interface): lexe_ln::esplora: Error broadcasting txs: Batch broadcast failed: Error broadcasting tx: txid=eb6451e9a7de40de78138dc3615c4261c38cad6947e95bcb6a8c8557dfeb93ba, num_inputs=1, num_outputs=2, inputs=[f7a25f4f4eee9ee1da0972076bfbf83e61b2ca589e4e591abb9e070e868d1129:0], outputs=[(4899939706 SAT, Script(OP_0 OP_PUSHBYTES_20 f3fa194cad5a39bf5c1a715fa0d261abc40648b5)), (60000 SAT, Script(OP_0 OP_PUSHBYTES_32 7a761d9a803aea29e02fac5f64039ae398460e62349dbd92798f52066923bc49))]: HttpResponse { status: 400, message: "sendrawtransaction RPC error: {\"code\":-26,\"message\":\"insufficient fee, rejecting replacement eb6451e9a7de40de78138dc3615c4261c38cad6947e95bcb6a8c8557dfeb93ba; new feerate 0.00001000 BTC/kvB <= old feerate 0.00001000 BTC/kvB\"}" } user_pk=a9edf959
2025-02-26T02:27:35.200058Z  INFO (lsp): common::task: Task '(broadcaster-interface)' finished user_pk=a9edf959
2025-02-26T02:27:35.200090Z DEBUG (lsp): common::task: Ephemeral task finished: (broadcaster-interface) user_pk=a9edf959

2025-02-26T02:27:40.699382Z DEBUG (lsp): common::task: Received ephemeral task: (broadcaster-interface) user_pk=a9edf959
2025-02-26T02:27:40.699482Z  INFO (lsp):(bgp):(event-handler)(chan-man):(broadcaster-interface):(broadcast-txs-inner): lexe_ln::esplora: Broadcasting batch of 1 txs user_pk=a9edf959
2025-02-26T02:27:40.704586Z  INFO (lsp):(bgp):(event-handler)(chan-man):(broadcaster-interface):(broadcast-txs-inner):(req)(cli): lxapi: Done (success) req_time=4.977ms status=200 user_pk=a9edf959 from=lsp to=backend method=PUT url=https://localhost:61146/lsp/events trace_id="Kq8I8EQlHmRVkQqK" attempts_left=1
2025-02-26T02:27:40.704667Z  INFO (lsp):(bgp):(event-handler)(chan-man):(broadcaster-interface):(broadcast-txs-inner): lexe_ln::esplora: Broadcasting transaction: txid=baf6da68b20ce0220cf723e0cc6169fbe7cc68c174d52206e11efad67ad21617, num_inputs=1, num_outputs=2, inputs=[f7a25f4f4eee9ee1da0972076bfbf83e61b2ca589e4e591abb9e070e868d1129:0], outputs=[(180000 SAT, Script(OP_0 OP_PUSHBYTES_32 f574a6a87c27d10e02a6c459f9fbf9bd2af224f7cefbaa1c97267b854e6e89b6)), (4899819706 SAT, Script(OP_0 OP_PUSHBYTES_20 d9c3717a2c3bf5645f7db5371baedbbf0d6557ca))] user_pk=a9edf959
2025-02-26T02:27:40.705939Z ERROR (lsp):(bgp):(event-handler)(chan-man):(broadcaster-interface): lexe_ln::esplora: Error broadcasting txs: Batch broadcast failed: Error broadcasting tx: txid=baf6da68b20ce0220cf723e0cc6169fbe7cc68c174d52206e11efad67ad21617, num_inputs=1, num_outputs=2, inputs=[f7a25f4f4eee9ee1da0972076bfbf83e61b2ca589e4e591abb9e070e868d1129:0], outputs=[(180000 SAT, Script(OP_0 OP_PUSHBYTES_32 f574a6a87c27d10e02a6c459f9fbf9bd2af224f7cefbaa1c97267b854e6e89b6)), (4899819706 SAT, Script(OP_0 OP_PUSHBYTES_20 d9c3717a2c3bf5645f7db5371baedbbf0d6557ca))]: HttpResponse { status: 400, message: "sendrawtransaction RPC error: {\"code\":-26,\"message\":\"insufficient fee, rejecting replacement baf6da68b20ce0220cf723e0cc6169fbe7cc68c174d52206e11efad67ad21617; new feerate 0.00001000 BTC/kvB <= old feerate 0.00001000 BTC/kvB\"}" } user_pk=a9edf959
2025-02-26T02:27:40.706037Z  INFO (lsp): common::task: Task '(broadcaster-interface)' finished user_pk=a9edf959
2025-02-26T02:27:40.706059Z DEBUG (lsp): common::task: Ephemeral task finished: (broadcaster-interface) user_pk=a9edf959
@MaxFangX
Copy link
Contributor Author

After some testing, I think the solution is to immediately trigger a BDK sync after the transaction is broadcasted, so BDK picks up the broadcasted tx from the mempool and marks the output as currently being spent. The next time a funding transaction is generated, BDK will correctly use another output. This applies in general - we should always resync whenever any transaction is broadcasted, whether it comes from LDK's BroadcasterInterface or whether it was initiated by the user in a normal onchain payment.

@MaxFangX
Copy link
Contributor Author

MaxFangX commented Feb 26, 2025

If there's an API to tell BDK that a particular transaction has been accepted into the mempool, we can avoid the overhead of doing an actual sync. I asked about it here.

Update: Will get around to trying to tomorrow, but I think we can set TxUpdate::txs to vec![Arc::new(tx)] and then apply it to the BDK wallet with Wallet::apply_update.

@tnull
Copy link
Collaborator

tnull commented Feb 26, 2025

Yes, this has been a known issue for years at this point, see my feature request here: bitcoindevkit/bdk#849

Unfortunately it got pushed back and back again, and is still pending a resolution on BDK's end.

Update: Will get around to trying to tomorrow, but I think we can set TxUpdate::txs to vec![Arc::new(tx)] and then apply it to the BDK wallet with Wallet::apply_update.

Hmm, I haven't closely looked at the BDK-internal code regarding this exact approach, but previous discussions concluded that there currently is no way you could 'unlock' the locked UTXOs again. This means that at the very least might need to keep track of which UTXOs you locked and then explicitly double-spend them again if the transaction never ends up confirming. I'm of the opinion that all of this tracking is really the concern of the onchain wallet itself, and hence should be handled by BDK internally.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants