From 5870ce0c6db59e2184e2bbafbf72b364142faf53 Mon Sep 17 00:00:00 2001 From: Gregory Hill Date: Tue, 5 Sep 2023 10:16:20 +0000 Subject: [PATCH] fix: migration for pruned nodes Signed-off-by: Gregory Hill --- bitcoin/src/electrs/types.rs | 4 ++-- bitcoin/src/lib.rs | 25 ++++++++++++++++++++++++- vault/src/system.rs | 9 ++++++++- 3 files changed, 34 insertions(+), 4 deletions(-) diff --git a/bitcoin/src/electrs/types.rs b/bitcoin/src/electrs/types.rs index 5320a3c61..83586a20d 100644 --- a/bitcoin/src/electrs/types.rs +++ b/bitcoin/src/electrs/types.rs @@ -15,7 +15,7 @@ pub struct TransactionStatus { } // https://github.com/Blockstream/electrs/blob/adedee15f1fe460398a7045b292604df2161adc0/src/rest.rs#L167-L189 -#[derive(Deserialize)] +#[derive(Deserialize, Clone)] pub struct TxInValue { pub txid: Txid, pub vout: u32, @@ -33,7 +33,7 @@ pub struct TxInValue { } // https://github.com/Blockstream/electrs/blob/adedee15f1fe460398a7045b292604df2161adc0/src/rest.rs#L239-L270 -#[derive(Deserialize)] +#[derive(Deserialize, Clone)] pub struct TxOutValue { pub scriptpubkey: ScriptBuf, pub scriptpubkey_asm: String, diff --git a/bitcoin/src/lib.rs b/bitcoin/src/lib.rs index fe5148c30..0ef0c1b6b 100644 --- a/bitcoin/src/lib.rs +++ b/bitcoin/src/lib.rs @@ -469,6 +469,11 @@ impl BitcoinCore { // Make sure signing is successful if signed_funded_raw_tx.errors.is_some() { + log::warn!( + "Received bitcoin funding errors (complete={}): {:?}", + signed_funded_raw_tx.complete, + signed_funded_raw_tx.errors + ); return Err(Error::TransactionSigningError); } @@ -1092,7 +1097,7 @@ impl BitcoinCoreApi for BitcoinCore { // filter to only import // a) payments in the blockchain (not in mempool), and // b) payments TO the address (as bitcoin core will already know about transactions spending FROM it) - let confirmed_payments_to = all_transactions.into_iter().filter(|tx| { + let confirmed_payments_to = all_transactions.iter().filter(|tx| { if let Some(status) = &tx.status { if !status.confirmed { return false; @@ -1113,6 +1118,24 @@ impl BitcoinCoreApi for BitcoinCore { &[serde_json::to_value(raw_tx)?, serde_json::to_value(raw_merkle_proof)?], )?; } + // TODO: remove this migration after the next runtime upgrade + // filter to remove spent funds, the previous wallet migration caused + // signing failures for pruned nodes because they tried to double spend + let confirmed_payments_from = all_transactions.iter().filter(|tx| { + if let Some(status) = &tx.status { + if !status.confirmed { + return false; + } + }; + tx.vin + .iter() + .filter_map(|input| input.prevout.clone()) + .any(|output| matches!(&output.scriptpubkey_address, Some(addr) if addr == &address)) + }); + for transaction in confirmed_payments_from { + self.rpc + .call("removeprunedfunds", &[serde_json::to_value(transaction.txid)?])?; + } } Ok(()) } diff --git a/vault/src/system.rs b/vault/src/system.rs index 156af48d0..45847904d 100644 --- a/vault/src/system.rs +++ b/vault/src/system.rs @@ -308,9 +308,10 @@ impl VaultIdManager { } tracing::info!("Merging wallet for {:?}", vault_id); + let all_addresses = btc_rpc.list_addresses()?; // issue keys should be imported separately but we need to iterate // through currency specific wallets to get change addresses - for address in btc_rpc.list_addresses()? { + for address in &all_addresses { tracing::info!("Found {:?}", address); // get private key from currency specific wallet let private_key = btc_rpc.dump_private_key(&address)?; @@ -318,6 +319,12 @@ impl VaultIdManager { btc_rpc_shared.import_private_key(&private_key, false)?; } + if btc_rpc_shared.get_pruned_height().await? != 0 { + // rescan via electrs to import or remove change utxos + // this is required because pruned nodes cannot rescan themselves + btc_rpc_shared.rescan_electrs_for_addresses(all_addresses).await?; + } + tracing::info!("Initializing metrics..."); let metrics = PerCurrencyMetrics::new(&vault_id); let data = VaultData {