Apply suggestions from code review

Co-authored-by: str4d <jack@electriccoin.co>
This commit is contained in:
Kris Nuttycombe 2022-01-03 15:46:28 -07:00 committed by Kris Nuttycombe
parent ad54591061
commit eb53abbbaf
8 changed files with 86 additions and 75 deletions

View File

@ -536,17 +536,19 @@ TEST(KeystoreTests, StoreAndRetrieveUFVK) {
auto addrPair = zufvk.FindAddress(diversifier_index_t(0), {ReceiverType::Sapling}).value();
EXPECT_TRUE(addrPair.first.GetSaplingReceiver().has_value());
auto saplingReceiver = addrPair.first.GetSaplingReceiver().value();
auto ufvkmeta = keyStore.GetUFVKMetadataForReceiver(saplingReceiver);
EXPECT_FALSE(ufvkmeta.has_value());
auto saplingIvk = zufvk.GetSaplingKey().value().fvk.in_viewing_key();
keyStore.AddSaplingIncomingViewingKey(saplingIvk, saplingReceiver);
auto ufvkmeta = keyStore.GetUFVKMetadataForReceiver(saplingReceiver);
ufvkmeta = keyStore.GetUFVKMetadataForReceiver(saplingReceiver);
EXPECT_TRUE(ufvkmeta.has_value());
EXPECT_EQ(ufvkmeta.value().first, ufvkid);
EXPECT_FALSE(ufvkmeta.value().second.has_value());
}
TEST(KeystoreTests, AddUnifiedAddress) {
TEST(KeystoreTests, AddTransparentReceiverForUnifiedAddress) {
SelectParams(CBaseChainParams::TESTNET);
CBasicKeyStore keyStore;
@ -559,10 +561,12 @@ TEST(KeystoreTests, AddUnifiedAddress) {
auto ufvkid = zufvk.GetKeyID();
auto addrPair = zufvk.FindAddress(diversifier_index_t(0), {ReceiverType::P2PKH, ReceiverType::Sapling}).value();
EXPECT_TRUE(addrPair.first.GetP2PKHReceiver().has_value());
keyStore.AddUnifiedAddress(ufvkid, addrPair.second, addrPair.first);
auto ufvkmeta = keyStore.GetUFVKMetadataForReceiver(addrPair.first.GetP2PKHReceiver().value());
EXPECT_FALSE(ufvkmeta.has_value());
keyStore.AddTransparentReceiverForUnifiedAddress(ufvkid, addrPair.second, addrPair.first);
ufvkmeta = keyStore.GetUFVKMetadataForReceiver(addrPair.first.GetP2PKHReceiver().value());
EXPECT_TRUE(ufvkmeta.has_value());
EXPECT_EQ(ufvkmeta.value().first, ufvkid);
}

View File

@ -316,7 +316,7 @@ bool CBasicKeyStore::AddUnifiedFullViewingKey(
return true;
}
bool CBasicKeyStore::AddUnifiedAddress(
bool CBasicKeyStore::AddTransparentReceiverForUnifiedAddress(
const libzcash::UFVKId& keyId,
const libzcash::diversifier_index_t& diversifierIndex,
const libzcash::UnifiedAddress& ua)
@ -361,10 +361,11 @@ CBasicKeyStore::GetUFVKMetadataForReceiver(const libzcash::Receiver& receiver) c
std::optional<std::pair<libzcash::UFVKId, std::optional<libzcash::diversifier_index_t>>>
FindUFVKId::operator()(const libzcash::SaplingPaymentAddress& saplingAddr) const {
if (keystore.mapSaplingIncomingViewingKeys.count(saplingAddr) > 0) {
const auto& saplingIvk = keystore.mapSaplingIncomingViewingKeys.at(saplingAddr);
if (keystore.mapSaplingKeyUnified.count(saplingIvk) > 0) {
return std::make_pair(keystore.mapSaplingKeyUnified.at(saplingIvk), std::nullopt);
const auto saplingIvk = keystore.mapSaplingIncomingViewingKeys.find(saplingAddr);
if (saplingIvk != keystore.mapSaplingIncomingViewingKeys.end()) {
const auto ufvkId = keystore.mapSaplingKeyUnified.find(saplingIvk->second);
if (ufvkId != keystore.mapSaplingKeyUnified.end()) {
return std::make_pair(ufvkId->second, std::nullopt);
} else {
return std::nullopt;
}
@ -374,16 +375,18 @@ FindUFVKId::operator()(const libzcash::SaplingPaymentAddress& saplingAddr) const
}
std::optional<std::pair<libzcash::UFVKId, std::optional<libzcash::diversifier_index_t>>>
FindUFVKId::operator()(const CScriptID& scriptId) const {
if (keystore.mapP2SHUnified.count(scriptId) > 0) {
return keystore.mapP2SHUnified.at(scriptId);
const auto metadata = keystore.mapP2SHUnified.find(scriptId);
if (metadata != keystore.mapP2SHUnified.end()) {
return metadata->second;
} else {
return std::nullopt;
}
}
std::optional<std::pair<libzcash::UFVKId, std::optional<libzcash::diversifier_index_t>>>
FindUFVKId::operator()(const CKeyID& keyId) const {
if (keystore.mapP2PKHUnified.count(keyId) > 0) {
return keystore.mapP2PKHUnified.at(keyId);
const auto metadata = keystore.mapP2PKHUnified.find(keyId);
if (metadata != keystore.mapP2PKHUnified.end()) {
return metadata->second;
} else {
return std::nullopt;
}

View File

@ -117,7 +117,7 @@ public:
* viewing key upon discovery of the address as having received
* funds.
*/
virtual bool AddUnifiedAddress(
virtual bool AddTransparentReceiverForUnifiedAddress(
const libzcash::UFVKId& keyId,
const libzcash::diversifier_index_t& diversifierIndex,
const libzcash::UnifiedAddress& ua) = 0;
@ -357,7 +357,7 @@ public:
virtual bool AddUnifiedFullViewingKey(
const libzcash::ZcashdUnifiedFullViewingKey &ufvk);
virtual bool AddUnifiedAddress(
virtual bool AddTransparentReceiverForUnifiedAddress(
const libzcash::UFVKId& keyId,
const libzcash::diversifier_index_t& diversifierIndex,
const libzcash::UnifiedAddress& ua);

View File

@ -182,7 +182,6 @@ TEST(WalletTests, SproutNoteDataSerialisation) {
EXPECT_EQ(noteData[jsoutpt].witnesses, noteData2[jsoutpt].witnesses);
}
TEST(WalletTests, FindUnspentSproutNotes) {
SelectParams(CBaseChainParams::TESTNET);
@ -356,9 +355,6 @@ TEST(WalletTests, FindUnspentSproutNotes) {
mapBlockIndex.erase(blockHash);
mapBlockIndex.erase(blockHash2);
mapBlockIndex.erase(blockHash3);
// Revert to default
RegtestDeactivateSapling();
}
@ -2232,4 +2228,7 @@ TEST(WalletTests, GenerateUnifiedAddress) {
expected = AddressGenerationError::DiversifierSpaceExhausted;
EXPECT_EQ(uaResult, expected);
}
// Revert to default
RegtestDeactivateSapling();
}

View File

@ -195,9 +195,7 @@ bool CWallet::AddSaplingZKey(const libzcash::SaplingExtendedSpendingKey &sk)
return true;
}
bool CWallet::AddSaplingFullViewingKey(
const libzcash::SaplingExtendedFullViewingKey &extfvk,
const std::optional<libzcash::UFVKId>& ufvkId)
bool CWallet::AddSaplingFullViewingKey(const libzcash::SaplingExtendedFullViewingKey &extfvk)
{
AssertLockHeld(cs_wallet);
@ -636,16 +634,16 @@ UAGenerationResult CWallet::GenerateUnifiedAddress(
return AddressGenerationError::NoAddressForDiversifier;
}
// Persist the newly created address to the keystore
mapUfvkAddressMetadata[ufvkid].SetReceivers(diversifierIndex, receiverTypes);
CCryptoKeyStore::AddUnifiedAddress(ufvkid, diversifierIndex, address.value());
assert(mapUfvkAddressMetadata[ufvkid].SetReceivers(diversifierIndex, receiverTypes));
// Writing this data is handled by `CWalletDB::WriteUnifiedAddressMetadata` below.
assert(CCryptoKeyStore::AddTransparentReceiverForUnifiedAddress(ufvkid, diversifierIndex, address.value()));
// Save the metadata for the generated address so that we can re-derive
// it in the future.
ZcashdUnifiedAddressMetadata addrmeta(ufvkid, diversifierIndex, receiverTypes);
if (fFileBacked && !CWalletDB(strWalletFile).WriteUnifiedAddressMetadata(addrmeta)) {
throw std::runtime_error(
"CWallet::AdddUnifiedAddress(): Writing unified address metadata failed");
"CWallet::AddUnifiedAddress(): Writing unified address metadata failed");
}
if (hasTransparent) {
@ -691,11 +689,14 @@ bool CWallet::LoadUnifiedFullViewingKey(const libzcash::UnifiedFullViewingKey &k
if (metadata != mapUfvkAddressMetadata.end()) {
// restore unified addresses that have been previously generated to the
// keystore
for (const auto &[j, receiverTypes] : metadata->second.GetAllReceivers()) {
for (const auto &[j, receiverTypes] : metadata->second.GetKnownReceiverSetsByDiversifierIndex()) {
auto addr = zufvk.Address(j, receiverTypes).value();
CCryptoKeyStore::AddUnifiedAddress(zufvk.GetKeyID(), j, addr);
if (!CCryptoKeyStore::AddTransparentReceiverForUnifiedAddress(zufvk.GetKeyID(), j, addr)) {
return false;
}
}
}
return CCryptoKeyStore::AddUnifiedFullViewingKey(zufvk);
}
@ -710,16 +711,18 @@ bool CWallet::LoadUnifiedAccountMetadata(const ZcashdUnifiedAccountMetadata &skm
bool CWallet::LoadUnifiedAddressMetadata(const ZcashdUnifiedAddressMetadata &addrmeta)
{
AssertLockHeld(cs_wallet);
mapUfvkAddressMetadata[addrmeta.GetKeyID()].SetReceivers(
if (!mapUfvkAddressMetadata[addrmeta.GetKeyID()].SetReceivers(
addrmeta.GetDiversifierIndex(),
addrmeta.GetReceiverTypes());
addrmeta.GetReceiverTypes())) {
return false;
}
auto ufvk = GetUnifiedFullViewingKey(addrmeta.GetKeyID());
if (ufvk.has_value()) {
// Regenerate the unified address and add it to the keystore.
auto j = addrmeta.GetDiversifierIndex();
auto addr = ufvk.value().Address(j, addrmeta.GetReceiverTypes()).value();
return CCryptoKeyStore::AddUnifiedAddress(addrmeta.GetKeyID(), j, addr);
return CCryptoKeyStore::AddTransparentReceiverForUnifiedAddress(addrmeta.GetKeyID(), j, addr);
}
return true;
@ -5862,21 +5865,19 @@ std::optional<libzcash::UnifiedAddress> LookupUnifiedAddress::operator()(const l
}
diversifier_index_t j;
auto metadata = wallet.mapUfvkAddressMetadata.find(ufvkid);
if (metadata != wallet.mapUfvkAddressMetadata.end()) {
librustzcash_sapling_diversifier_index(
ufvk.value().GetSaplingKey().value().dk.begin(),
saplingAddr.d.begin(),
j.begin());
auto receivers = metadata->second.GetReceivers(j);
if (receivers.has_value()) {
return ufvk.value().Address(j, receivers.value());
} else {
// If we don't know the receiver types at which the address was originally
// generated, we can't reconstruct the address.
return std::nullopt;
}
// If the wallet is missing metadata at this UFVK id, it is probably
// corrupt and the node should shut down.
const auto& metadata = wallet.mapUfvkAddressMetadata.at(ufvkid);
librustzcash_sapling_diversifier_index(
ufvk.value().GetSaplingKey().value().dk.begin(),
saplingAddr.d.begin(),
j.begin());
auto receivers = metadata.GetReceivers(j);
if (receivers.has_value()) {
return ufvk.value().Address(j, receivers.value());
} else {
// If we don't know the receiver types at which the address was originally
// generated, we can't reconstruct the address.
return std::nullopt;
}
} else {
@ -5899,17 +5900,16 @@ std::optional<libzcash::UnifiedAddress> LookupUnifiedAddress::operator()(const C
throw std::runtime_error("CWallet::LookupUnifiedAddress(): UFVK has no P2PKH key part.");
}
// Find the set of receivers at the diversifier index. If no metadata is available
// for the ufvk, or we do not know the receiver types for the address produced
// at this diversifier, we cannot reconstruct the address.
auto metadata = wallet.mapUfvkAddressMetadata.find(ufvkid);
if (metadata != wallet.mapUfvkAddressMetadata.end()) {
auto receivers = metadata->second.GetReceivers(j);
if (receivers.has_value()) {
return ufvk.value().Address(j, receivers.value());
} else {
return std::nullopt;
}
// If the wallet is missing metadata at this UFVK id, it is probably
// corrupt and the node should shut down.
const auto& metadata = wallet.mapUfvkAddressMetadata.at(ufvkid);
// Find the set of receivers at the diversifier index. If we do not
// know the receiver types for the address produced at this
// diversifier, we cannot reconstruct the address.
auto receivers = metadata.GetReceivers(j);
if (receivers.has_value()) {
return ufvk.value().Address(j, receivers.value());
} else {
return std::nullopt;
}

View File

@ -685,13 +685,21 @@ public:
class UFVKAddressMetadata
{
private:
// The account ID may be absent for imported UFVKs, and also may temporarily
// be absent when this data structure is in a partially-reconstructed state
// during the wallet load process.
std::optional<libzcash::AccountId> accountId;
std::map<libzcash::diversifier_index_t, std::set<libzcash::ReceiverType>> addressReceivers;
public:
UFVKAddressMetadata() {}
UFVKAddressMetadata(libzcash::AccountId accountId): accountId(accountId) {}
const std::map<libzcash::diversifier_index_t, std::set<libzcash::ReceiverType>>& GetAllReceivers() const {
/**
* Return all currently known diversifier indices for which addresses
* have been generated, each accompanied by the associated set of receiver
* types that were used when generating that address.
*/
const std::map<libzcash::diversifier_index_t, std::set<libzcash::ReceiverType>>& GetKnownReceiverSetsByDiversifierIndex() const {
return addressReceivers;
}
@ -715,10 +723,11 @@ public:
bool SetReceivers(
const libzcash::diversifier_index_t& j,
const std::set<libzcash::ReceiverType>& receivers) {
if (addressReceivers.count(j) > 0) {
return addressReceivers[j] == receivers;
const auto [it, success] = addressReceivers.insert(std::make_pair(j, receivers));
if (success) {
return true;
} else {
return addressReceivers.insert(std::make_pair(j, receivers)).second;
return it->second == receivers;
}
}
@ -742,12 +751,7 @@ public:
if (addressReceivers.empty()) {
return libzcash::diversifier_index_t(0);
} else {
auto lastIndex = addressReceivers.rbegin()->first;
if (lastIndex.increment()) {
return lastIndex;
} else {
return std::nullopt;
}
return addressReceivers.rbegin()->first.succ();
}
}
};
@ -1167,8 +1171,7 @@ public:
//! CBasicKeyStore::AddSaplingFullViewingKey is called directly when adding a
//! full viewing key to the keystore, to avoid this override.
bool AddSaplingFullViewingKey(
const libzcash::SaplingExtendedFullViewingKey &extfvk,
const std::optional<libzcash::UFVKId>& ufvkId = std::nullopt);
const libzcash::SaplingExtendedFullViewingKey &extfvk);
bool AddSaplingIncomingViewingKey(
const libzcash::SaplingIncomingViewingKey &ivk,
const libzcash::SaplingPaymentAddress &addr);
@ -1199,8 +1202,10 @@ public:
std::pair<libzcash::ZcashdUnifiedSpendingKey, libzcash::AccountId>
GenerateNewUnifiedSpendingKey();
//! Generate the next available unified spending key from the wallet's
//! mnemonic seed.
//! Generate the unified spending key for the specified ZIP-32/BIP-44
//! account identifier from the wallet's mnemonic seed, or returns
//! std::nullopt if the account identifier does not produce a valid
//! spending key for all receiver types.
std::optional<libzcash::ZcashdUnifiedSpendingKey>
GenerateUnifiedSpendingKeyForAccount(libzcash::AccountId accountId);

View File

@ -21,11 +21,11 @@ bool libzcash::HasShielded(const std::set<ReceiverType>& receiverTypes) {
}
bool libzcash::HasTransparent(const std::set<ReceiverType>& receiverTypes) {
auto has_shielded = [](ReceiverType r) {
auto has_transparent = [](ReceiverType r) {
// TODO: update this as support for new transparent protocols is added.
return r == ReceiverType::P2PKH || r == ReceiverType::P2SH;
};
return std::find_if(receiverTypes.begin(), receiverTypes.end(), has_shielded) != receiverTypes.end();
return std::find_if(receiverTypes.begin(), receiverTypes.end(), has_transparent) != receiverTypes.end();
}
std::optional<ZcashdUnifiedSpendingKey> ZcashdUnifiedSpendingKey::ForAccount(
@ -132,5 +132,5 @@ std::optional<std::pair<UnifiedAddress, diversifier_index_t>> ZcashdUnifiedFullV
std::optional<std::pair<UnifiedAddress, diversifier_index_t>> ZcashdUnifiedFullViewingKey::FindAddress(
const diversifier_index_t& j) const {
return FindAddress(j, {ReceiverType::P2PKH, ReceiverType::Sapling, ReceiverType::Orchard});
return FindAddress(j, {ReceiverType::P2PKH, ReceiverType::Sapling});
}

View File

@ -15,7 +15,7 @@ enum class ReceiverType: uint32_t {
P2PKH = 0x00,
P2SH = 0x01,
Sapling = 0x02,
Orchard = 0x03
//Orchard = 0x03
};
/**