From 007f2b31af9a15fd497d0bc932ff719dca2a0809 Mon Sep 17 00:00:00 2001 From: Duke Date: Sat, 31 May 2025 11:50:38 -0400 Subject: [PATCH] Keep a list of notes we are spending and must lock which is different from the list of all notes we might spend --- src/wallet/asyncrpcoperation_sendmany.cpp | 33 +++++++++++++---------- src/wallet/asyncrpcoperation_sendmany.h | 4 +++ 2 files changed, 23 insertions(+), 14 deletions(-) diff --git a/src/wallet/asyncrpcoperation_sendmany.cpp b/src/wallet/asyncrpcoperation_sendmany.cpp index 349e2e010..f97795ab6 100644 --- a/src/wallet/asyncrpcoperation_sendmany.cpp +++ b/src/wallet/asyncrpcoperation_sendmany.cpp @@ -234,14 +234,8 @@ bool AsyncRPCOperation_sendmany::main_impl() { throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Insufficient funds, no unspent notes found for zaddr from address."); } - // Now that find_unspent_notes() has run, we now know which - // notes need to be locked - // Lock UTXOs lock_utxos(); - // Lock shielded input notes - lock_notes(); - LogPrint("zrpc", "%s: z_sendmany input notes locked\n", getId()); CAmount t_inputs_total = 0; for (SendManyInputUTXO & t : t_inputs_) { @@ -412,7 +406,14 @@ bool AsyncRPCOperation_sendmany::main_impl() { std::vector ops; std::vector notes; CAmount sum = 0; - for (auto t : z_sapling_inputs_) { + + //NOTE: z_sapling_inputs_ is a list of all potential notes to spend + // saplingNoteInputs_ is a list of notes we will actually spend + // and need to lock. It is a subset of z_sapling_inputs_ + for (const auto t : z_sapling_inputs_) { + // keep track of notes to lock later on in lock_notes() + saplingNoteInputs_.emplace_back(t.op, t.note, t.note.value() ); + ops.push_back(t.op); notes.push_back(t.note); sum += t.note.value(); @@ -421,6 +422,9 @@ bool AsyncRPCOperation_sendmany::main_impl() { } } + // Lock shielded input notes (zins) stored in saplingNoteInputs + lock_notes(); + // Fetch Sapling anchor and witnesses //LogPrintf("%s: Gathering anchors and witnesses\n", __FUNCTION__); uint256 anchor; @@ -665,9 +669,10 @@ bool AsyncRPCOperation_sendmany::find_unspent_notes() { pwalletMain->GetFilteredNotes(saplingEntries, fromaddress_, mindepth_); } - // store sapling inputs so we can correctly lock and unlock them + for (auto entry : saplingEntries) { z_sapling_inputs_.push_back(entry); + std::string data(entry.memo.begin(), entry.memo.end()); LogPrint("zrpcunsafe", "%s: found unspent Sapling note (txid=%s, vShieldedSpend=%d, amount=%s, memo=%s)\n", getId(), @@ -805,17 +810,17 @@ void AsyncRPCOperation_sendmany::unlock_utxos() { // Lock input notes void AsyncRPCOperation_sendmany::lock_notes() { LOCK2(cs_main, pwalletMain->cs_wallet); - fprintf(stderr,"%s: found %lu notes to lock\n", __func__, z_sapling_inputs_.size() ); - for (auto note : z_sapling_inputs_) { - pwalletMain->LockNote(note.op); + fprintf(stderr,"%s: found %lu notes to lock\n", __func__, saplingNoteInputs_.size() ); + for (auto note : saplingNoteInputs_) { + pwalletMain->LockNote(std::get<0>(note)); } } // Unlock input notes void AsyncRPCOperation_sendmany::unlock_notes() { LOCK2(cs_main, pwalletMain->cs_wallet); - fprintf(stderr,"%s: found %lu notes to unlock\n", __func__, z_sapling_inputs_.size() ); - for (auto note : z_sapling_inputs_) { - pwalletMain->UnlockNote(note.op); + fprintf(stderr,"%s: found %lu notes to unlock\n", __func__, saplingNoteInputs_.size() ); + for (auto note : saplingNoteInputs_) { + pwalletMain->UnlockNote(std::get<0>(note)); } } diff --git a/src/wallet/asyncrpcoperation_sendmany.h b/src/wallet/asyncrpcoperation_sendmany.h index 42ae2e505..271daba3d 100644 --- a/src/wallet/asyncrpcoperation_sendmany.h +++ b/src/wallet/asyncrpcoperation_sendmany.h @@ -45,6 +45,9 @@ typedef std::tuple SendManyRecipient; // Input UTXO is a tuple (quadruple) of txid, vout, amount, coinbase) typedef std::tuple SendManyInputUTXO; +// Input note is a tuple of output, note, amount +typedef std::tuple SendManyInputSaplingNote; + class AsyncRPCOperation_sendmany : public AsyncRPCOperation { public: AsyncRPCOperation_sendmany( @@ -93,6 +96,7 @@ private: std::vector z_outputs_; std::vector t_inputs_; std::vector z_sapling_inputs_; + std::vector saplingNoteInputs_; TransactionBuilder builder_; CTransaction tx_;