Add caching and updating of Sapling note nullifier.
This commit is contained in:
parent
f9816408b2
commit
ad1e90dd34
|
@ -474,8 +474,10 @@ void CWallet::ChainTip(const CBlockIndex *pindex,
|
|||
{
|
||||
if (added) {
|
||||
IncrementNoteWitnesses(pindex, pblock, sproutTree, saplingTree);
|
||||
UpdateSaplingNullifierNoteMapForBlock(pblock);
|
||||
} else {
|
||||
DecrementNoteWitnesses(pindex);
|
||||
UpdateSaplingNullifierNoteMapForBlock(pblock);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1169,6 +1171,10 @@ bool CWallet::UpdateNullifierNoteMap()
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Sapling. This method is only called from RPC walletpassphrase, which is currently unsupported
|
||||
// as RPC encryptwallet is hidden behind two flags: -developerencryptwallet -experimentalfeatures
|
||||
|
||||
UpdateNullifierNoteMapWithTx(wtxItem.second);
|
||||
}
|
||||
}
|
||||
|
@ -1176,7 +1182,8 @@ bool CWallet::UpdateNullifierNoteMap()
|
|||
}
|
||||
|
||||
/**
|
||||
* Update mapSproutNullifiersToNotes with the cached nullifiers in this tx.
|
||||
* Update mapSproutNullifiersToNotes and mapSaplingNullifiersToNotes
|
||||
* with the cached nullifiers in this tx.
|
||||
*/
|
||||
void CWallet::UpdateNullifierNoteMapWithTx(const CWalletTx& wtx)
|
||||
{
|
||||
|
@ -1187,6 +1194,71 @@ void CWallet::UpdateNullifierNoteMapWithTx(const CWalletTx& wtx)
|
|||
mapSproutNullifiersToNotes[*item.second.nullifier] = item.first;
|
||||
}
|
||||
}
|
||||
|
||||
for (const mapSaplingNoteData_t::value_type& item : wtx.mapSaplingNoteData) {
|
||||
if (item.second.nullifier) {
|
||||
mapSaplingNullifiersToNotes[*item.second.nullifier] = item.first;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update mapSaplingNullifiersToNotes, computing the nullifier from a cached witness if necessary.
|
||||
*/
|
||||
void CWallet::UpdateSaplingNullifierNoteMapWithTx(CWalletTx& wtx) {
|
||||
LOCK(cs_wallet);
|
||||
|
||||
for (mapSaplingNoteData_t::value_type &item : wtx.mapSaplingNoteData) {
|
||||
SaplingOutPoint op = item.first;
|
||||
SaplingNoteData nd = item.second;
|
||||
|
||||
if (nd.witnesses.size() == 0) {
|
||||
// If there are no witnesses, erase the nullifier and associated mapping.
|
||||
if (item.second.nullifier) {
|
||||
mapSaplingNullifiersToNotes.erase(item.second.nullifier.get());
|
||||
}
|
||||
item.second.nullifier = boost::none;
|
||||
}
|
||||
else if (nd.witnesses.size() > 0) {
|
||||
uint64_t position = nd.witnesses.front().position();
|
||||
SaplingFullViewingKey fvk = mapSaplingFullViewingKeys.at(nd.ivk);
|
||||
OutputDescription output = wtx.vShieldedOutput[op.n];
|
||||
auto optPlaintext = SaplingNotePlaintext::decrypt(output.encCiphertext, nd.ivk, output.ephemeralKey, output.cm);
|
||||
if (!optPlaintext) {
|
||||
// An item in mapSaplingNoteData must have already been successfully decrypted,
|
||||
// otherwise the item would not exist in the first place.
|
||||
assert(false);
|
||||
}
|
||||
auto optNote = optPlaintext.get().note(nd.ivk);
|
||||
if (!optNote) {
|
||||
assert(false);
|
||||
}
|
||||
auto optNullifier = optNote.get().nullifier(fvk, position);
|
||||
if (!optNullifier) {
|
||||
// This should not happen. If it does, maybe the position has been corrupted or miscalculated?
|
||||
assert(false);
|
||||
}
|
||||
uint256 nullifier = optNullifier.get();
|
||||
mapSaplingNullifiersToNotes[nullifier] = op;
|
||||
item.second.nullifier = nullifier;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterate over transactions in a block and update the cached Sapling nullifiers
|
||||
* for transactions which belong to the wallet.
|
||||
*/
|
||||
void CWallet::UpdateSaplingNullifierNoteMapForBlock(const CBlock *pblock) {
|
||||
LOCK(cs_wallet);
|
||||
|
||||
for (const CTransaction& tx : pblock->vtx) {
|
||||
auto hash = tx.GetHash();
|
||||
bool txIsOurs = mapWallet.count(hash);
|
||||
if (txIsOurs) {
|
||||
UpdateSaplingNullifierNoteMapWithTx(mapWallet[hash]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -270,12 +270,14 @@ public:
|
|||
* We initialize the height to -1 for the same reason as we do in SproutNoteData.
|
||||
* See the comment in that class for a full description.
|
||||
*/
|
||||
SaplingNoteData() : witnessHeight {-1} { }
|
||||
SaplingNoteData(libzcash::SaplingIncomingViewingKey ivk) : ivk {ivk}, witnessHeight {-1} { }
|
||||
SaplingNoteData() : witnessHeight {-1}, nullifier() { }
|
||||
SaplingNoteData(libzcash::SaplingIncomingViewingKey ivk) : ivk {ivk}, witnessHeight {-1}, nullifier() { }
|
||||
SaplingNoteData(libzcash::SaplingIncomingViewingKey ivk, uint256 n) : ivk {ivk}, witnessHeight {-1}, nullifier(n) { }
|
||||
|
||||
std::list<SaplingWitness> witnesses;
|
||||
int witnessHeight;
|
||||
libzcash::SaplingIncomingViewingKey ivk;
|
||||
boost::optional<uint256> nullifier;
|
||||
|
||||
friend bool operator==(const SaplingNoteData& a, const SaplingNoteData& b) {
|
||||
return (a.ivk == b.ivk && a.nullifier == b.nullifier && a.witnessHeight == b.witnessHeight);
|
||||
|
@ -1050,6 +1052,8 @@ public:
|
|||
void MarkDirty();
|
||||
bool UpdateNullifierNoteMap();
|
||||
void UpdateNullifierNoteMapWithTx(const CWalletTx& wtx);
|
||||
void UpdateSaplingNullifierNoteMapWithTx(CWalletTx& tx);
|
||||
void UpdateSaplingNullifierNoteMapForBlock(const CBlock* pblock);
|
||||
bool AddToWallet(const CWalletTx& wtxIn, bool fFromLoadWallet, CWalletDB* pwalletdb);
|
||||
void SyncTransaction(const CTransaction& tx, const CBlock* pblock);
|
||||
bool AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pblock, bool fUpdate);
|
||||
|
|
Loading…
Reference in New Issue