From e63d52896a3caa1d932233e40c82779eb31e0fd0 Mon Sep 17 00:00:00 2001 From: Kris Nuttycombe Date: Wed, 9 Mar 2022 13:59:05 -0700 Subject: [PATCH] Restore mined block heights when restoring decrypted notes. --- src/rust/include/rust/orchard/wallet.h | 4 ++++ src/rust/src/wallet.rs | 29 ++++++++++++++++++++++---- src/wallet/orchard.h | 4 ++++ src/wallet/wallet.cpp | 7 ++++++- 4 files changed, 39 insertions(+), 5 deletions(-) diff --git a/src/rust/include/rust/orchard/wallet.h b/src/rust/include/rust/orchard/wallet.h index e64eaff4a..3759433a0 100644 --- a/src/rust/include/rust/orchard/wallet.h +++ b/src/rust/include/rust/orchard/wallet.h @@ -117,9 +117,13 @@ void orchard_wallet_add_notes_from_bundle( * * The provided bundle must be a component of the transaction from which * `txid` was derived. + * + * The value the `blockHeight` pointer points to be set to the height at which the + * transaction was mined, or `nullptr` if the transaction is not in the main chain. */ bool orchard_wallet_restore_notes( OrchardWalletPtr* wallet, + const uint32_t* blockHeight, const unsigned char txid[32], const OrchardBundlePtr* bundle, const RawOrchardActionIVK* actionIvks, diff --git a/src/rust/src/wallet.rs b/src/rust/src/wallet.rs index 28a358056..d9f886557 100644 --- a/src/rust/src/wallet.rs +++ b/src/rust/src/wallet.rs @@ -341,7 +341,15 @@ impl Wallet { let mut result = BTreeMap::new(); for (action_idx, ivk, note, recipient, memo) in bundle.decrypt_outputs_for_keys(&keys) { - assert!(self.add_decrypted_note(txid, action_idx, ivk.clone(), note, recipient, memo)); + assert!(self.add_decrypted_note( + None, + txid, + action_idx, + ivk.clone(), + note, + recipient, + memo + )); result.insert(action_idx, ivk); } @@ -353,13 +361,22 @@ impl Wallet { /// key to the vector of action indices that that key decrypts. pub fn add_notes_from_bundle_with_hints( &mut self, + tx_height: Option, txid: &TxId, bundle: &Bundle, hints: BTreeMap, ) -> Result<(), BundleDecryptionError> { for (action_idx, ivk) in hints.into_iter() { if let Some((note, recipient, memo)) = bundle.decrypt_output_with_key(action_idx, ivk) { - if !self.add_decrypted_note(txid, action_idx, ivk.clone(), note, recipient, memo) { + if !self.add_decrypted_note( + tx_height, + txid, + action_idx, + ivk.clone(), + note, + recipient, + memo, + ) { return Err(BundleDecryptionError::FvkNotFound(ivk.clone())); } } else { @@ -369,8 +386,10 @@ impl Wallet { Ok(()) } + #[allow(clippy::too_many_arguments)] fn add_decrypted_note( &mut self, + tx_height: Option, txid: &TxId, action_idx: usize, ivk: IncomingViewingKey, @@ -396,7 +415,7 @@ impl Wallet { self.wallet_received_notes .entry(*txid) .or_insert_with(|| TxNotes { - tx_height: None, + tx_height, decrypted_notes: BTreeMap::new(), }) .decrypted_notes @@ -639,12 +658,14 @@ pub extern "C" fn orchard_wallet_add_notes_from_bundle( #[no_mangle] pub extern "C" fn orchard_wallet_restore_notes( wallet: *mut Wallet, + block_height: *const u32, txid: *const [c_uchar; 32], bundle: *const Bundle, hints: *const FFIActionIvk, hints_len: usize, ) -> bool { let wallet = unsafe { wallet.as_mut() }.expect("Wallet pointer may not be null"); + let block_height = unsafe { block_height.as_ref() }.map(|h| BlockHeight::from(*h)); let txid = TxId::from_bytes(*unsafe { txid.as_ref() }.expect("txid may not be null.")); let bundle = unsafe { bundle.as_ref() }.expect("bundle pointer may not be null."); @@ -658,7 +679,7 @@ pub extern "C" fn orchard_wallet_restore_notes( ); } - match wallet.add_notes_from_bundle_with_hints(&txid, bundle, hints) { + match wallet.add_notes_from_bundle_with_hints(block_height, &txid, bundle, hints) { Ok(_) => true, Err(e) => { error!("Failed to restore decrypted notes to wallet: {:?}", e); diff --git a/src/wallet/orchard.h b/src/wallet/orchard.h index 812c96c4a..4bfc765cb 100644 --- a/src/wallet/orchard.h +++ b/src/wallet/orchard.h @@ -133,6 +133,7 @@ public: * notes to the wallet. */ bool RestoreDecryptedNotes( + const std::optional nBlockHeight, const CTransaction& tx, std::map hints ) { @@ -140,8 +141,10 @@ public: for (const auto& [action_idx, ivk] : hints) { rawHints.push_back({ action_idx, ivk.inner.get() }); } + uint32_t blockHeight = nBlockHeight.has_value() ? (uint32_t) nBlockHeight.value() : 0; return orchard_wallet_restore_notes( inner.get(), + nBlockHeight.has_value() ? &blockHeight : nullptr, tx.GetHash().begin(), tx.GetOrchardBundle().inner.get(), rawHints.data(), @@ -156,6 +159,7 @@ public: * Returns `false` if the caller attempts to insert a block out-of-order. */ bool AppendNoteCommitments(const int nBlockHeight, const CBlock& block) { + assert(nBlockHeight >= 0); for (int txidx = 0; txidx < block.vtx.size(); txidx++) { const CTransaction& tx = block.vtx[txidx]; if (!orchard_wallet_append_bundle_commitments( diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index a53ac73b8..3f447861b 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -947,7 +947,12 @@ bool CWallet::LoadUnifiedCaches() // Restore decrypted Orchard notes. for (const auto& [_, walletTx] : mapWallet) { if (!walletTx.mapOrchardActionData.empty()) { - if (!orchardWallet.RestoreDecryptedNotes(walletTx, walletTx.mapOrchardActionData)) { + const CBlockIndex* pTxIndex; + std::optional blockHeight; + if (walletTx.GetDepthInMainChain(pTxIndex) > 0) { + blockHeight = pTxIndex->nHeight; + } + if (!orchardWallet.RestoreDecryptedNotes(blockHeight, walletTx, walletTx.mapOrchardActionData)) { return false; } }