RPC: Use OutgoingViewingKeys to recover non-wallet Sapling outputs
This commit is contained in:
parent
f77915c587
commit
347de0aae2
|
@ -3553,6 +3553,7 @@ UniValue z_viewtransaction(const UniValue& params, bool fHelp)
|
|||
" \"jsOutput\" : n, (numeric, sprout) the index of the output within the JSDescription\n"
|
||||
" \"output\" : n, (numeric, sapling) the index of the output within the vShieldedOutput\n"
|
||||
" \"address\" : \"zcashaddress\", (string) The Zcash address involved in the transaction\n"
|
||||
" \"outgoing\" : true|false (boolean, sapling) True if the output is not for an address in the wallet\n"
|
||||
" \"value\" : x.xxx (numeric) The amount in " + CURRENCY_UNIT + "\n"
|
||||
" \"valueZat\" : xxxx (numeric) The amount in zatoshis\n"
|
||||
" \"memo\" : \"hexmemo\", (string) Hexademical string representation of the memo field\n"
|
||||
|
@ -3651,6 +3652,14 @@ UniValue z_viewtransaction(const UniValue& params, bool fHelp)
|
|||
outputs.push_back(entry);
|
||||
}
|
||||
|
||||
// Collect OutgoingViewingKeys for recovering output information
|
||||
std::set<uint256> ovks;
|
||||
{
|
||||
// Generate the common ovk for recovering t->z outputs.
|
||||
HDSeed seed = pwalletMain->GetHDSeedForRPC();
|
||||
ovks.insert(ovkForShieldingFromTaddr(seed));
|
||||
}
|
||||
|
||||
// Sapling spends
|
||||
for (size_t i = 0; i < wtx.vShieldedSpend.size(); ++i) {
|
||||
auto spend = wtx.vShieldedSpend[i];
|
||||
|
@ -3663,10 +3672,15 @@ UniValue z_viewtransaction(const UniValue& params, bool fHelp)
|
|||
auto op = res->second;
|
||||
auto wtxPrev = pwalletMain->mapWallet.at(op.hash);
|
||||
|
||||
auto decrypted = wtxPrev.DecryptSaplingNote(op);
|
||||
auto decrypted = wtxPrev.DecryptSaplingNote(op).get();
|
||||
auto notePt = decrypted.first;
|
||||
auto pa = decrypted.second;
|
||||
|
||||
// Store the OutgoingViewingKey for recovering outputs
|
||||
libzcash::SaplingFullViewingKey fvk;
|
||||
assert(pwalletMain->GetSaplingFullViewingKey(wtxPrev.mapSaplingNoteData.at(op).ivk, fvk));
|
||||
ovks.insert(fvk.ovk);
|
||||
|
||||
UniValue entry(UniValue::VOBJ);
|
||||
entry.push_back(Pair("type", ADDR_TYPE_SAPLING));
|
||||
entry.push_back(Pair("spend", (int)i));
|
||||
|
@ -3679,17 +3693,36 @@ UniValue z_viewtransaction(const UniValue& params, bool fHelp)
|
|||
}
|
||||
|
||||
// Sapling outputs
|
||||
for (auto & pair : wtx.mapSaplingNoteData) {
|
||||
SaplingOutPoint op = pair.first;
|
||||
for (uint32_t i = 0; i < wtx.vShieldedOutput.size(); ++i) {
|
||||
auto op = SaplingOutPoint(hash, i);
|
||||
|
||||
SaplingNotePlaintext notePt;
|
||||
SaplingPaymentAddress pa;
|
||||
bool isOutgoing;
|
||||
|
||||
auto decrypted = wtx.DecryptSaplingNote(op);
|
||||
auto notePt = decrypted.first;
|
||||
auto pa = decrypted.second;
|
||||
if (decrypted) {
|
||||
notePt = decrypted->first;
|
||||
pa = decrypted->second;
|
||||
isOutgoing = false;
|
||||
} else {
|
||||
// Try recovering the output
|
||||
auto recovered = wtx.RecoverSaplingNote(op, ovks);
|
||||
if (recovered) {
|
||||
notePt = recovered->first;
|
||||
pa = recovered->second;
|
||||
isOutgoing = true;
|
||||
} else {
|
||||
// Unreadable
|
||||
continue;
|
||||
}
|
||||
}
|
||||
auto memo = notePt.memo();
|
||||
|
||||
UniValue entry(UniValue::VOBJ);
|
||||
entry.push_back(Pair("type", ADDR_TYPE_SAPLING));
|
||||
entry.push_back(Pair("output", (int)op.n));
|
||||
entry.push_back(Pair("outgoing", isOutgoing));
|
||||
entry.push_back(Pair("address", EncodePaymentAddress(pa)));
|
||||
entry.push_back(Pair("value", ValueFromAmount(notePt.value())));
|
||||
entry.push_back(Pair("valueZat", notePt.value()));
|
||||
|
|
|
@ -2258,9 +2258,15 @@ std::pair<SproutNotePlaintext, SproutPaymentAddress> CWalletTx::DecryptSproutNot
|
|||
}
|
||||
}
|
||||
|
||||
std::pair<SaplingNotePlaintext, SaplingPaymentAddress> CWalletTx::DecryptSaplingNote(
|
||||
SaplingOutPoint op) const
|
||||
boost::optional<std::pair<
|
||||
SaplingNotePlaintext,
|
||||
SaplingPaymentAddress>> CWalletTx::DecryptSaplingNote(SaplingOutPoint op) const
|
||||
{
|
||||
// Check whether we can decrypt this SaplingOutPoint
|
||||
if (this->mapSaplingNoteData.count(op) == 0) {
|
||||
return boost::none;
|
||||
}
|
||||
|
||||
auto output = this->vShieldedOutput[op.n];
|
||||
auto nd = this->mapSaplingNoteData.at(op);
|
||||
|
||||
|
@ -2279,6 +2285,40 @@ std::pair<SaplingNotePlaintext, SaplingPaymentAddress> CWalletTx::DecryptSapling
|
|||
return std::make_pair(notePt, pa);
|
||||
}
|
||||
|
||||
boost::optional<std::pair<
|
||||
SaplingNotePlaintext,
|
||||
SaplingPaymentAddress>> CWalletTx::RecoverSaplingNote(
|
||||
SaplingOutPoint op, std::set<uint256>& ovks) const
|
||||
{
|
||||
auto output = this->vShieldedOutput[op.n];
|
||||
|
||||
for (auto ovk : ovks) {
|
||||
auto outPt = SaplingOutgoingPlaintext::decrypt(
|
||||
output.outCiphertext,
|
||||
ovk,
|
||||
output.cv,
|
||||
output.cm,
|
||||
output.ephemeralKey);
|
||||
if (!outPt) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto maybe_pt = SaplingNotePlaintext::decrypt(
|
||||
output.encCiphertext,
|
||||
output.ephemeralKey,
|
||||
outPt->esk,
|
||||
outPt->pk_d,
|
||||
output.cm);
|
||||
assert(static_cast<bool>(maybe_pt));
|
||||
auto notePt = maybe_pt.get();
|
||||
|
||||
return std::make_pair(notePt, SaplingPaymentAddress(notePt.d, outPt->pk_d));
|
||||
}
|
||||
|
||||
// Couldn't recover with any of the provided OutgoingViewingKeys
|
||||
return boost::none;
|
||||
}
|
||||
|
||||
int64_t CWalletTx::GetTxTime() const
|
||||
{
|
||||
int64_t n = nTimeSmart;
|
||||
|
|
|
@ -557,8 +557,13 @@ public:
|
|||
|
||||
std::pair<libzcash::SproutNotePlaintext, libzcash::SproutPaymentAddress> DecryptSproutNote(
|
||||
JSOutPoint jsop) const;
|
||||
std::pair<libzcash::SaplingNotePlaintext, libzcash::SaplingPaymentAddress> DecryptSaplingNote(
|
||||
SaplingOutPoint op) const;
|
||||
boost::optional<std::pair<
|
||||
libzcash::SaplingNotePlaintext,
|
||||
libzcash::SaplingPaymentAddress>> DecryptSaplingNote(SaplingOutPoint op) const;
|
||||
boost::optional<std::pair<
|
||||
libzcash::SaplingNotePlaintext,
|
||||
libzcash::SaplingPaymentAddress>> RecoverSaplingNote(
|
||||
SaplingOutPoint op, std::set<uint256>& ovks) const;
|
||||
|
||||
//! filter decides which addresses will count towards the debit
|
||||
CAmount GetDebit(const isminefilter& filter) const;
|
||||
|
|
Loading…
Reference in New Issue