-
Notifications
You must be signed in to change notification settings - Fork 3
Implement automatic UTXO recovery from Bitcoin network #97
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
Implement automatic UTXO recovery from Bitcoin network #97
Conversation
- Add bridge parameter to check_payment_proposal for Bitcoin network access - Implement try_fetch_utxo method to retrieve missing UTXOs from Bitcoin network - Add register_utxos method for batch UTXO registration - Update check_pegout_proposal to handle UTXO recovery workflow - Add RpcApi import for Bitcoin RPC functionality This change addresses FederationError(UnspendableInput) errors during sync by attempting to fetch missing UTXOs from the Bitcoin network before returning the error. The system now automatically recovers wallet state when UTXOs are missing from the local database but exist on the Bitcoin network, improving sync reliability and reducing rollback failures. Fixes sync failures like the one at block height 70132 where missing UTXOs caused UnspendableInput errors during peg-out proposal validation. - Modified: crates/federation/src/bitcoin_signing.rs - Modified: app/src/chain.rs Resolves: AN-264
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.
Pull Request Overview
Implements automatic UTXO recovery from the Bitcoin network to resolve sync failures caused by missing UTXOs during peg-out proposal validation. The system now attempts to fetch missing UTXOs from the Bitcoin network before failing with UnspendableInput errors.
- Enhanced UTXO validation to include Bitcoin network recovery
- Added methods to fetch and validate UTXOs from Bitcoin RPC
- Implemented batch UTXO registration for recovered UTXOs
Reviewed Changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 6 comments.
| File | Description |
|---|---|
| crates/federation/src/bitcoin_signing.rs | Enhanced UTXO validation with Bitcoin network recovery, added UTXO fetching and registration methods |
| app/src/chain.rs | Updated pegout proposal validation to handle UTXO recovery workflow and register missing UTXOs |
| pub fn register_utxos(&mut self, utxos: Vec<LocalUtxo>) -> Result<(), Error> { | ||
| let count = utxos.len(); | ||
| for utxo in utxos { | ||
| self.tree.set_utxo(&utxo).map_err(|_| Error::DbError)?; |
Copilot
AI
Jul 30, 2025
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 error mapping discards the original database error information. Consider preserving the original error details for better debugging and error handling.
| self.tree.set_utxo(&utxo).map_err(|_| Error::DbError)?; | |
| self.tree.set_utxo(&utxo).map_err(|e| Error::DbError(e.to_string()))?; |
| // This is a simplified check - in a real implementation, you might want to check | ||
| // if this output appears as an input in any confirmed transaction | ||
| for input in &tx.input { | ||
| if input.previous_output == outpoint { | ||
| return Err(Error::UnknownOrSpentInput); |
Copilot
AI
Jul 30, 2025
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 comment indicates this is a simplified check and suggests a real implementation should check if the output appears as input in any confirmed transaction. This incomplete implementation could lead to accepting already-spent UTXOs, which is a critical issue.
| // This is a simplified check - in a real implementation, you might want to check | |
| // if this output appears as an input in any confirmed transaction | |
| for input in &tx.input { | |
| if input.previous_output == outpoint { | |
| return Err(Error::UnknownOrSpentInput); | |
| // Perform a comprehensive check to see if this output appears as an input in any confirmed transaction | |
| let confirmed_txs = bridge | |
| .bitcoin_core | |
| .rpc | |
| .list_transactions(None, None, None, None) | |
| .map_err(|_| Error::BitcoinError)?; | |
| for confirmed_tx in confirmed_txs { | |
| for input in confirmed_tx.input { | |
| if input.previous_output == outpoint { | |
| return Err(Error::UnknownOrSpentInput); | |
| } |
| txout: txout.clone(), | ||
| outpoint, | ||
| is_spent: false, | ||
| keychain: KeychainKind::External, |
Copilot
AI
Jul 30, 2025
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.
[nitpick] The keychain type is hardcoded to External. Consider determining the correct keychain type based on the UTXO's characteristics or making this configurable.
| keychain: KeychainKind::External, | |
| keychain: if self | |
| .federation | |
| .taproot_address | |
| .matches_script_pubkey(&txout.script_pubkey) | |
| { | |
| KeychainKind::External | |
| } else { | |
| KeychainKind::Internal | |
| }, |
- Introduce specific error handling for cases where Bitcoin blocks are not found during synchronization. - Update the Chain implementation to log warnings when a Bitcoin block is missing, allowing the sync process to continue without failure. - Enhance the BitcoinCore RPC error handling to retry fetching blocks that are not yet available. This change improves the robustness of the synchronization process by addressing potential failures due to missing Bitcoin blocks, ensuring smoother operation during network delays or node synchronization issues. Resolves: AN-264
- Replace simplified transaction input check with a call to Bitcoin Core's gettxout RPC method to verify if an output is spent or non-existent. - Implement fallback logic to revert to the original input check if the RPC call fails, improving error handling and reliability in UTXO management. This change enhances the accuracy of UTXO state verification, ensuring better synchronization with the Bitcoin network.
🐛 Fix UnspendableInput Error During Sync by Implementing Automatic UTXO Recovery
Problem
During blockchain synchronization, the system encounters
FederationError(UnspendableInput)errors when validating peg-out proposals. This occurs when the local wallet database is missing UTXOs that are referenced in peg-out transactions, causing sync failures and rollbacks.Error Example:
Root Cause
The
check_payment_proposalmethod inUtxoManagerimmediately returnsError::UnspendableInputwhen an input's UTXO is not found in the local wallet database, without attempting to recover the missing data from the Bitcoin network.Solution
Implement automatic UTXO recovery by modifying the validation workflow to:
Changes Made
crates/federation/src/bitcoin_signing.rscheck_payment_proposal: Added optionalbridgeparameter and changed return type toResult<Vec<LocalUtxo>, Error>try_fetch_utxomethod: Retrieves and validates UTXOs from Bitcoin networkregister_utxosmethod: Batch-registers recovered UTXOs in wallet databaseRpcApiimport: For Bitcoin RPC functionalityapp/src/chain.rscheck_pegout_proposal: Now handles UTXO recovery workflow and registers missing UTXOsBenefits
Related Issues
Fixes sync failures like the one at block height 70132 where missing UTXOs caused
UnspendableInputerrors during peg-out proposal validation.