Skip to content

Commit

Permalink
[Wallet] Back port FindMySaplingNotes().
Browse files Browse the repository at this point in the history
  • Loading branch information
furszy committed Oct 14, 2020
1 parent 2c4bab7 commit 82714ff
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 1 deletion.
45 changes: 45 additions & 0 deletions src/sapling/saplingscriptpubkeyman.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "sapling/saplingscriptpubkeyman.h"
#include "sapling/note.hpp"
#include "chain.h" // for CBlockIndex
#include "validation.h" // for ReadBlockFromDisk()

Expand Down Expand Up @@ -212,6 +213,50 @@ void SaplingScriptPubKeyMan::DecrementNoteWitnesses(const CBlockIndex* pindex)
// of the wallet.dat is maintained).
}

/**
* Finds all output notes in the given transaction that have been sent to
* SaplingPaymentAddresses in this wallet.
*
* It should never be necessary to call this method with a CWalletTx, because
* the result of FindMySaplingNotes (for the addresses available at the time) will
* already have been cached in CWalletTx.mapSaplingNoteData.
*/
std::pair<mapSaplingNoteData_t, SaplingIncomingViewingKeyMap> SaplingScriptPubKeyMan::FindMySaplingNotes(const CTransaction &tx) const
{
LOCK(wallet->cs_KeyStore);
uint256 hash = tx.GetHash();

mapSaplingNoteData_t noteData;
SaplingIncomingViewingKeyMap viewingKeysToAdd;

// Protocol Spec: 4.19 Block Chain Scanning (Sapling)
for (uint32_t i = 0; i < tx.sapData->vShieldedOutput.size(); ++i) {
const OutputDescription output = tx.sapData->vShieldedOutput[i];
for (auto it = wallet->mapSaplingFullViewingKeys.begin(); it != wallet->mapSaplingFullViewingKeys.end(); ++it) {
libzcash::SaplingIncomingViewingKey ivk = it->first;
auto result = libzcash::SaplingNotePlaintext::decrypt(output.encCiphertext, ivk, output.ephemeralKey, output.cmu);
if (!result) {
continue;
}

// Check if we already have it.
auto address = ivk.address(result.get().d);
if (address && wallet->mapSaplingIncomingViewingKeys.count(address.get()) == 0) {
viewingKeysToAdd[address.get()] = ivk;
}
// We don't cache the nullifier here as computing it requires knowledge of the note position
// in the commitment tree, which can only be determined when the transaction has been mined.
SaplingOutPoint op {hash, i};
SaplingNoteData nd;
nd.ivk = ivk;
noteData.insert(std::make_pair(op, nd));
break;
}
}

return std::make_pair(noteData, viewingKeysToAdd);
}

bool SaplingScriptPubKeyMan::UpdatedNoteData(const CWalletTx& wtxIn, CWalletTx& wtx)
{
bool unchangedSaplingFlag = (wtxIn.mapSaplingNoteData.empty() || wtxIn.mapSaplingNoteData == wtx.mapSaplingNoteData);
Expand Down
6 changes: 6 additions & 0 deletions src/sapling/saplingscriptpubkeyman.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,8 @@ enum KeyAddResult {
KeyNotAdded,
};

typedef std::map<SaplingOutPoint, SaplingNoteData> mapSaplingNoteData_t;

/*
* Sapling keys manager
* todo: add real description..
Expand Down Expand Up @@ -176,6 +178,10 @@ class SaplingScriptPubKeyMan {
//! Return the spending key for the payment address (nullopt if the wallet has no spending key for such address)
Optional<libzcash::SaplingExtendedSpendingKey> GetSpendingKeyForPaymentAddress(const libzcash::SaplingPaymentAddress &addr) const;

//! Finds all output notes in the given tx that have been sent to a
//! SaplingPaymentAddress in this wallet
std::pair<mapSaplingNoteData_t, SaplingIncomingViewingKeyMap> FindMySaplingNotes(const CTransaction& tx) const;

//! Update note data if is needed
bool UpdatedNoteData(const CWalletTx& wtxIn, CWalletTx& wtx);

Expand Down
22 changes: 21 additions & 1 deletion src/wallet/wallet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -965,7 +965,22 @@ bool CWallet::AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlockIndex

bool fExisted = mapWallet.count(tx.GetHash()) != 0;
if (fExisted && !fUpdate) return false;
if (fExisted || IsMine(tx) || IsFromMe(tx)) {

// Check tx for Sapling notes
mapSaplingNoteData_t saplingNoteData;
if (HasSaplingSPKM()) {
auto saplingNoteDataAndAddressesToAdd = m_sspk_man->FindMySaplingNotes(tx);
saplingNoteData = saplingNoteDataAndAddressesToAdd.first;
auto addressesToAdd = saplingNoteDataAndAddressesToAdd.second;
// Add my addresses addresses
for (const auto &addressToAdd : addressesToAdd) {
if (!m_sspk_man->AddSaplingIncomingViewingKey(addressToAdd.second, addressToAdd.first)) {
return false;
}
}
}

if (fExisted || IsMine(tx) || IsFromMe(tx) || saplingNoteData.size() > 0) {

/* Check if any keys in the wallet keypool that were supposed to be unused
* have appeared in a new transaction. If so, remove those keys from the keypool.
Expand All @@ -979,6 +994,11 @@ bool CWallet::AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlockIndex
}

CWalletTx wtx(this, tx);

if (saplingNoteData.size() > 0) {
wtx.SetSaplingNoteData(saplingNoteData);
}

// Get merkle branch if transaction was found in a block
if (posInBlock != -1)
wtx.SetMerkleBranch(pIndex, posInBlock);
Expand Down

0 comments on commit 82714ff

Please sign in to comment.