Delay caching of nullifiers when wallet is locked

Closes #1502
This commit is contained in:
Jack Grigg
2016-10-11 21:49:14 -05:00
parent 8f445ee774
commit 1a62587e9a
5 changed files with 226 additions and 23 deletions

View File

@@ -863,12 +863,47 @@ void CWallet::MarkDirty()
}
}
/**
* Ensure that every note in the wallet has a cached nullifier.
*/
bool CWallet::UpdateNullifierNoteMap()
{
{
LOCK(cs_wallet);
if (IsLocked())
return false;
ZCNoteDecryption dec;
for (std::pair<const uint256, CWalletTx>& wtxItem : mapWallet) {
for (mapNoteData_t::value_type& item : wtxItem.second.mapNoteData) {
if (!item.second.nullifier) {
auto i = item.first.js;
GetNoteDecryptor(item.second.address, dec);
auto hSig = wtxItem.second.vjoinsplit[i].h_sig(
*pzcashParams, wtxItem.second.joinSplitPubKey);
item.second.nullifier = GetNoteNullifier(
wtxItem.second.vjoinsplit[i],
item.second.address,
dec,
hSig,
item.first.n);
}
}
UpdateNullifierNoteMap(wtxItem.second);
}
}
return true;
}
void CWallet::UpdateNullifierNoteMap(const CWalletTx& wtx)
{
{
LOCK(cs_wallet);
for (const mapNoteData_t::value_type& item : wtx.mapNoteData) {
mapNullifiersToNotes[item.second.nullifier] = item.first;
if (item.second.nullifier) {
mapNullifiersToNotes[*item.second.nullifier] = item.first;
}
}
}
}
@@ -1092,6 +1127,32 @@ void CWallet::EraseFromWallet(const uint256 &hash)
}
/**
* Returns a nullifier if the SpendingKey is available
* Throws std::runtime_error if the decryptor doesn't match this note
*/
boost::optional<uint256> CWallet::GetNoteNullifier(const JSDescription& jsdesc,
const libzcash::PaymentAddress& address,
const ZCNoteDecryption& dec,
const uint256& hSig,
uint8_t n) const
{
boost::optional<uint256> ret;
auto note_pt = libzcash::NotePlaintext::decrypt(
dec,
jsdesc.ciphertexts[n],
jsdesc.ephemeralKey,
hSig,
(unsigned char) n);
auto note = note_pt.note(address);
// SpendingKeys are only available if the wallet is unlocked
libzcash::SpendingKey key;
if (GetSpendingKey(address, key)) {
ret = note.nullifier(key);
}
return ret;
}
/**
* Finds all output notes in the given transaction that have been sent to
* PaymentAddresses in this wallet.
@@ -1106,28 +1167,28 @@ mapNoteData_t CWallet::FindMyNotes(const CTransaction& tx) const
uint256 hash = tx.GetHash();
mapNoteData_t noteData;
libzcash::SpendingKey key;
for (size_t i = 0; i < tx.vjoinsplit.size(); i++) {
auto hSig = tx.vjoinsplit[i].h_sig(*pzcashParams, tx.joinSplitPubKey);
for (uint8_t j = 0; j < tx.vjoinsplit[i].ciphertexts.size(); j++) {
for (const NoteDecryptorMap::value_type& item : mapNoteDecryptors) {
try {
auto note_pt = libzcash::NotePlaintext::decrypt(
item.second,
tx.vjoinsplit[i].ciphertexts[j],
tx.vjoinsplit[i].ephemeralKey,
hSig,
(unsigned char) j);
auto address = item.first;
// Decryptors are only cached when SpendingKeys are added
assert(GetSpendingKey(address, key));
auto note = note_pt.note(address);
JSOutPoint jsoutpt {hash, i, j};
CNoteData nd {address, note.nullifier(key)};
noteData.insert(std::make_pair(jsoutpt, nd));
auto nullifier = GetNoteNullifier(
tx.vjoinsplit[i],
address,
item.second,
hSig, j);
if (nullifier) {
CNoteData nd {address, *nullifier};
noteData.insert(std::make_pair(jsoutpt, nd));
} else {
CNoteData nd {address};
noteData.insert(std::make_pair(jsoutpt, nd));
}
break;
} catch (const std::runtime_error &) {
// Couldn't decrypt with this spending key
// Couldn't decrypt with this decryptor
} catch (const std::exception &exc) {
// Unexpected failure
LogPrintf("FindMyNotes(): Unexpected error while testing decrypt:\n");
@@ -3335,7 +3396,7 @@ void CWallet::GetFilteredNotes(std::vector<CNotePlaintextEntry> & outEntries, st
}
// skip note which has been spent
if (ignoreSpent && IsSpent(nd.nullifier)) {
if (ignoreSpent && nd.nullifier && IsSpent(*nd.nullifier)) {
continue;
}