wallet: stop zsTxSpendsToJSON inserting into the nullifier and note maps
zsTxSpendsToJSON looked spends up with operator[]: every foreign nullifier in a listed tx inserted a null outpoint into mapSaplingNullifiersToNotes, and the note-data lookup could insert an empty SaplingNoteData. A read-only RPC was mutating wallet state. z_viewtransaction then found those null outpoints and failed with RPC -1 "map::at" for every tx with a foreign Sapling spend (most incoming z->z payments) once z_listsentbyaddress or getalldata had run, until restart. ObsidianDragon treats that error as transient and retried those txs on every refresh. Use find() with the same test as IsSaplingNullifierFromMe(). This call produces the same rows in every case; z_viewtransaction now answers as it does on a freshly started daemon. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -148,12 +148,16 @@ void zsTxSpendsToJSON(const CWalletTx& wtx, UniValue& spends, CAmount& totalSpen
|
||||
const SpendDescription& spendDesc = wtx.vShieldedSpend[i];
|
||||
UniValue obj(UniValue::VOBJ);
|
||||
|
||||
SaplingOutPoint op = pwalletMain->mapSaplingNullifiersToNotes[spendDesc.nullifier];
|
||||
std::map<uint256, SaplingOutPoint>::const_iterator nfIt = pwalletMain->mapSaplingNullifiersToNotes.find(spendDesc.nullifier);
|
||||
|
||||
if (pwalletMain->IsSaplingNullifierFromMe(spendDesc.nullifier)) {
|
||||
const CWalletTx* parent = pwalletMain->GetWalletTx(pwalletMain->mapSaplingNullifiersToNotes[spendDesc.nullifier].hash);
|
||||
// Same test as IsSaplingNullifierFromMe(), but find() so a read-only RPC never inserts into wallet maps.
|
||||
if (nfIt != pwalletMain->mapSaplingNullifiersToNotes.end() && pwalletMain->mapWallet.count(nfIt->second.hash)) {
|
||||
const SaplingOutPoint op = nfIt->second;
|
||||
const CWalletTx* parent = pwalletMain->GetWalletTx(op.hash);
|
||||
mapSaplingNoteData_t::const_iterator ndIt = parent->mapSaplingNoteData.find(op);
|
||||
if (ndIt == parent->mapSaplingNoteData.end()) continue; // stale entry: old code inserted an empty note that never decrypts
|
||||
const OutputDescription& output = parent->vShieldedOutput[op.n];
|
||||
const SaplingNoteData& nd = pwalletMain->mapWallet[pwalletMain->mapSaplingNullifiersToNotes[spendDesc.nullifier].hash].mapSaplingNoteData[op];
|
||||
const SaplingNoteData& nd = ndIt->second;
|
||||
auto pt = libzcash::SaplingNotePlaintext::decrypt(output.encCiphertext,nd.ivk,output.ephemeralKey,output.cm);
|
||||
|
||||
if (pt) {
|
||||
|
||||
Reference in New Issue
Block a user