Return txid for already-known raw broadcasts
Problem
trezor_sign_tx_from_psbt returns a valid serialized signed transaction but normally leaves TrezorSignedTx.txid unset. This matches the current contract: the txid is populated only when signing also pushes the transaction.
The native apps broadcast separately and retain the signed transaction after an ambiguous network failure. If Electrum accepted the first broadcast but its response was lost, retrying can return an “already known”, “already in mempool”, or “already in blockchain” error. The apps then cannot complete transfer bookkeeping because they do not have the txid.
Requiring TrezorSignedTx.txid at signing time is not valid and breaks normal hardware signing.
Proposed change
Update broadcast_raw_tx in src/modules/onchain/implementation.rs:
- Decode and deserialize the signed transaction as it already does.
- Compute its canonical txid with
bitcoin::Transaction::compute_txid().
- Return the computed txid after a successful Electrum broadcast.
- Treat only explicit duplicate/already-accepted Electrum responses as success and return the computed txid.
- Preserve existing errors for invalid transaction data, connectivity failures, task failures, and unrelated broadcast rejection.
Keep TrezorSignedTx.txid optional and preserve its existing contract. Do not implement Bitcoin transaction parsing independently in Swift or Kotlin.
Error classification
Extract duplicate-response classification into a focused helper. Cover the Electrum messages currently handled by the apps:
already in block chain
already in blockchain
already in mempool
already-in-block-chain
already-in-mempool
txn-already-known
transaction already exists
Classification must be case-insensitive and must not convert unrelated relay-policy or invalid-transaction errors into success.
Tests
- A valid legacy transaction returns its canonical txid.
- A valid SegWit transaction returns
txid, not wtxid.
- Each supported already-known response returns the locally computed txid.
- Connectivity and unrelated broadcast errors remain failures.
- Invalid hex and invalid serialized transactions retain their typed errors.
Acceptance criteria
- Retrying an already-accepted raw transaction returns the same txid as the original broadcast.
- Native apps can complete Blocktank funding bookkeeping without relying on
TrezorSignedTx.txid.
- No FFI API shape change is required.
- Rust tests, Clippy, and formatting pass.
Consumer follow-up
After releasing Bitkit Core:
- Update the Core dependency in
bitkit-ios and bitkit-android.
- Remove app-level already-known error parsing and signer-provided txid recovery.
- Keep regression tests where Trezor signing returns
txid = nil and broadcast retry still completes.
Return txid for already-known raw broadcasts
Problem
trezor_sign_tx_from_psbtreturns a valid serialized signed transaction but normally leavesTrezorSignedTx.txidunset. This matches the current contract: the txid is populated only when signing also pushes the transaction.The native apps broadcast separately and retain the signed transaction after an ambiguous network failure. If Electrum accepted the first broadcast but its response was lost, retrying can return an “already known”, “already in mempool”, or “already in blockchain” error. The apps then cannot complete transfer bookkeeping because they do not have the txid.
Requiring
TrezorSignedTx.txidat signing time is not valid and breaks normal hardware signing.Proposed change
Update
broadcast_raw_txinsrc/modules/onchain/implementation.rs:bitcoin::Transaction::compute_txid().Keep
TrezorSignedTx.txidoptional and preserve its existing contract. Do not implement Bitcoin transaction parsing independently in Swift or Kotlin.Error classification
Extract duplicate-response classification into a focused helper. Cover the Electrum messages currently handled by the apps:
already in block chainalready in blockchainalready in mempoolalready-in-block-chainalready-in-mempooltxn-already-knowntransaction already existsClassification must be case-insensitive and must not convert unrelated relay-policy or invalid-transaction errors into success.
Tests
txid, notwtxid.Acceptance criteria
TrezorSignedTx.txid.Consumer follow-up
After releasing Bitkit Core:
bitkit-iosandbitkit-android.txid = niland broadcast retry still completes.