Add unified address generation.
Generate unified addresses from UFVKs, and add the associated metadata to the wallet database.
This commit is contained in:
parent
ca20cf512c
commit
b29ca10b8d
|
@ -309,7 +309,7 @@ bool CBasicKeyStore::AddUnifiedFullViewingKey(
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CBasicKeyStore::AddUnifiedAddress(
|
void CBasicKeyStore::AddUnifiedAddress(
|
||||||
const libzcash::UFVKId& keyId,
|
const libzcash::UFVKId& keyId,
|
||||||
const libzcash::UnifiedAddress& ua)
|
const libzcash::UnifiedAddress& ua)
|
||||||
{
|
{
|
||||||
|
@ -331,3 +331,13 @@ bool CBasicKeyStore::AddUnifiedAddress(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::optional<libzcash::ZcashdUnifiedFullViewingKey> CBasicKeyStore::GetUnifiedFullViewingKey(
|
||||||
|
const libzcash::UFVKId& keyId)
|
||||||
|
{
|
||||||
|
auto mi = mapUnifiedFullViewingKeys.find(keyId);
|
||||||
|
if (mi != mapUnifiedFullViewingKeys.end()) {
|
||||||
|
return mi->second;
|
||||||
|
} else {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -108,10 +108,13 @@ public:
|
||||||
const libzcash::ZcashdUnifiedFullViewingKey &ufvk
|
const libzcash::ZcashdUnifiedFullViewingKey &ufvk
|
||||||
) = 0;
|
) = 0;
|
||||||
|
|
||||||
virtual bool AddUnifiedAddress(
|
virtual void AddUnifiedAddress(
|
||||||
const libzcash::UFVKId& keyId,
|
const libzcash::UFVKId& keyId,
|
||||||
const libzcash::UnifiedAddress &ua
|
const libzcash::UnifiedAddress &ua
|
||||||
) = 0;
|
) = 0;
|
||||||
|
|
||||||
|
virtual std::optional<libzcash::ZcashdUnifiedFullViewingKey> GetUnifiedFullViewingKey(
|
||||||
|
const libzcash::UFVKId& keyId) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::map<CKeyID, CKey> KeyMap;
|
typedef std::map<CKeyID, CKey> KeyMap;
|
||||||
|
@ -346,9 +349,12 @@ public:
|
||||||
* Add the transparent component of the unified address, if any,
|
* Add the transparent component of the unified address, if any,
|
||||||
* to the keystore to make it possible to identify the
|
* to the keystore to make it possible to identify the
|
||||||
*/
|
*/
|
||||||
virtual bool AddUnifiedAddress(
|
virtual void AddUnifiedAddress(
|
||||||
const libzcash::UFVKId& keyId,
|
const libzcash::UFVKId& keyId,
|
||||||
const libzcash::UnifiedAddress &ua);
|
const libzcash::UnifiedAddress &ua);
|
||||||
|
|
||||||
|
virtual std::optional<libzcash::ZcashdUnifiedFullViewingKey> GetUnifiedFullViewingKey(
|
||||||
|
const libzcash::UFVKId& keyId);
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::vector<unsigned char, secure_allocator<unsigned char> > CKeyingMaterial;
|
typedef std::vector<unsigned char, secure_allocator<unsigned char> > CKeyingMaterial;
|
||||||
|
|
|
@ -474,7 +474,7 @@ std::optional<std::pair<libzcash::ZcashdUnifiedSpendingKey, ZcashdUnifiedSpendin
|
||||||
// the fingerprint of the associated full viewing key.
|
// the fingerprint of the associated full viewing key.
|
||||||
|
|
||||||
auto metaKey = std::make_pair(skmeta.GetSeedFingerprint(), skmeta.GetAccountId());
|
auto metaKey = std::make_pair(skmeta.GetSeedFingerprint(), skmeta.GetAccountId());
|
||||||
mapUnifiedKeyMetadata.insert({ufvkid, skmeta});
|
mapUnifiedKeyMetadata.insert({metaKey, skmeta});
|
||||||
|
|
||||||
// Add Transparent component to the wallet
|
// Add Transparent component to the wallet
|
||||||
if (sk.GetTransparentKey().has_value()) {
|
if (sk.GetTransparentKey().has_value()) {
|
||||||
|
@ -532,17 +532,117 @@ bool CWallet::AddUnifiedFullViewingKey(const libzcash::UnifiedFullViewingKey &uf
|
||||||
return CWalletDB(strWalletFile).WriteUnifiedFullViewingKey(ufvk);
|
return CWalletDB(strWalletFile).WriteUnifiedFullViewingKey(ufvk);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CWallet::LoadUnifiedFullViewingKey(const libzcash::UnifiedFullViewingKey &key)
|
std::optional<std::pair<UFVKId, ZcashdUnifiedFullViewingKey>> CWallet::GetUnifiedFullViewingKeyByAccount(libzcash::AccountId accountId) {
|
||||||
{
|
if (!mnemonicHDChain.has_value()) {
|
||||||
auto keyId = key.GetKeyID(Params());
|
throw std::runtime_error(
|
||||||
auto zufvk = ZcashdUnifiedFullViewingKey::FromUnifiedFullViewingKey(key);
|
"CWallet::GenerateNewUnifiedSpendingKey(): Wallet is missing mnemonic seed metadata.");
|
||||||
return CCryptoKeyStore::AddUnifiedFullViewingKey(keyId, zufvk);
|
}
|
||||||
|
|
||||||
|
auto seedfp = mnemonicHDChain.value().GetSeedFingerprint();
|
||||||
|
auto i = mapUnifiedKeyMetadata.find(std::make_pair(seedfp, accountId));
|
||||||
|
if (i != mapUnifiedKeyMetadata.end()) {
|
||||||
|
auto keyId = i->second.GetKeyID();
|
||||||
|
auto key = CCryptoKeyStore::GetUnifiedFullViewingKey(keyId);
|
||||||
|
if (key.has_value()) {
|
||||||
|
return std::make_pair(keyId, key.value());
|
||||||
|
} else {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CWallet::LoadUnifiedKeyMetadata(const ZcashdUnifiedSpendingKeyMetadata &meta)
|
UAGenerationResult CWallet::GenerateUnifiedAddress(
|
||||||
|
const libzcash::AccountId& accountId,
|
||||||
|
const libzcash::diversifier_index_t& j,
|
||||||
|
const std::set<libzcash::ReceiverType>& receiverTypes)
|
||||||
|
{
|
||||||
|
if (!libzcash::HasShielded(receiverTypes)) {
|
||||||
|
return AddressGenerationError::InvalidReceiverTypes;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto identifiedKey = GetUnifiedFullViewingKeyByAccount(accountId);
|
||||||
|
if (identifiedKey.has_value()) {
|
||||||
|
auto ufvkid = identifiedKey.value().first;
|
||||||
|
auto ufvk = identifiedKey.value().second;
|
||||||
|
|
||||||
|
// Check whether an address has already been generated for this
|
||||||
|
// diversifier index. If so, ensure that the set of receiver types
|
||||||
|
// being requested is the same as the set of receiver types that was
|
||||||
|
// previously generated; if so, return the previously generated address,
|
||||||
|
// otherwise return an error.
|
||||||
|
if (mapUnifiedAddressMetadata.count(ufvkid) > 0) {
|
||||||
|
const auto& accountKeys = mapUnifiedAddressMetadata.at(ufvkid);
|
||||||
|
if (accountKeys.count(j) > 0) {
|
||||||
|
if (accountKeys.at(j) == receiverTypes) {
|
||||||
|
ZcashdUnifiedAddressMetadata addrmeta(ufvkid, j, receiverTypes);
|
||||||
|
auto addr = ufvk.Address(j, receiverTypes);
|
||||||
|
return std::make_pair(addr.value(), addrmeta);
|
||||||
|
} else {
|
||||||
|
return AddressGenerationError::ExistingAddressMismatch;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find a working diversifier and construct the associated address.
|
||||||
|
auto found = ufvk.FindAddress(j, receiverTypes);
|
||||||
|
auto diversifierIndex = found.second;
|
||||||
|
|
||||||
|
// Persist the newly created address to the keystore
|
||||||
|
AddUnifiedAddress(ufvkid, found.first);
|
||||||
|
|
||||||
|
// Save the metadata for the generated address so that we can re-derive
|
||||||
|
// it in the future.
|
||||||
|
ZcashdUnifiedAddressMetadata addrmeta(ufvkid, found.second, receiverTypes);
|
||||||
|
mapUnifiedAddressMetadata[ufvkid].insert({diversifierIndex, receiverTypes});
|
||||||
|
if (fFileBacked) {
|
||||||
|
CWalletDB(strWalletFile).WriteUnifiedAddressMetadata(addrmeta);
|
||||||
|
}
|
||||||
|
return std::make_pair(found.first, addrmeta);
|
||||||
|
} else {
|
||||||
|
return AddressGenerationError::NoSuchAccount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CWallet::LoadUnifiedFullViewingKey(const libzcash::UnifiedFullViewingKey &key)
|
||||||
|
{
|
||||||
|
auto ufvkid = key.GetKeyID(Params());
|
||||||
|
auto zufvk = ZcashdUnifiedFullViewingKey::FromUnifiedFullViewingKey(key);
|
||||||
|
if (mapUnifiedAddressMetadata.count(ufvkid) > 0) {
|
||||||
|
// restore unified addresses that have been previously generated to the
|
||||||
|
// keystore
|
||||||
|
for (const auto &[j, receiverTypes] : mapUnifiedAddressMetadata[ufvkid]) {
|
||||||
|
auto addr = zufvk.Address(j, receiverTypes).value();
|
||||||
|
AddUnifiedAddress(ufvkid, addr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return CCryptoKeyStore::AddUnifiedFullViewingKey(ufvkid, zufvk);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CWallet::LoadUnifiedKeyMetadata(const ZcashdUnifiedSpendingKeyMetadata &skmeta)
|
||||||
{
|
{
|
||||||
AssertLockHeld(cs_wallet); // mapUnifiedKeyMetadata
|
AssertLockHeld(cs_wallet); // mapUnifiedKeyMetadata
|
||||||
mapUnifiedKeyMetadata.insert({meta.GetKeyID(), meta});
|
auto metaKey = std::make_pair(skmeta.GetSeedFingerprint(), skmeta.GetAccountId());
|
||||||
|
mapUnifiedKeyMetadata.insert({metaKey, skmeta});
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CWallet::LoadUnifiedAddressMetadata(const ZcashdUnifiedAddressMetadata &addrmeta)
|
||||||
|
{
|
||||||
|
AssertLockHeld(cs_wallet); // mapUnifiedKeyMetadata
|
||||||
|
auto ufvk = GetUnifiedFullViewingKey(addrmeta.GetKeyID());
|
||||||
|
if (ufvk.has_value()) {
|
||||||
|
// restore unified addresses that have been previously generated
|
||||||
|
auto addr = ufvk.value().Address(addrmeta.GetDiversifierIndex(), addrmeta.GetReceiverTypes());
|
||||||
|
if (addr.has_value()) {
|
||||||
|
AddUnifiedAddress(addrmeta.GetKeyID(), addr.value());
|
||||||
|
} else {
|
||||||
|
// an error has occurred; the ufvk is loaded but cannot reproduce the
|
||||||
|
// address identified by the address metadata.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CWallet::LoadKeyMetadata(const CPubKey &pubkey, const CKeyMetadata &meta)
|
void CWallet::LoadKeyMetadata(const CPubKey &pubkey, const CKeyMetadata &meta)
|
||||||
|
|
|
@ -402,6 +402,17 @@ public:
|
||||||
bool AcceptToMemoryPool(bool fLimitFree=true, bool fRejectAbsurdFee=true);
|
bool AcceptToMemoryPool(bool fLimitFree=true, bool fRejectAbsurdFee=true);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class AddressGenerationError {
|
||||||
|
NoSuchAccount,
|
||||||
|
InvalidReceiverTypes,
|
||||||
|
ExistingAddressMismatch,
|
||||||
|
NoSaplingAddressForDiversifier
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef std::variant<
|
||||||
|
std::pair<libzcash::UnifiedAddress, ZcashdUnifiedAddressMetadata>,
|
||||||
|
AddressGenerationError> UAGenerationResult;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A transaction with a bunch of additional info that only the owner cares about.
|
* A transaction with a bunch of additional info that only the owner cares about.
|
||||||
* It includes any unrecorded transactions needed to link it back to the block chain.
|
* It includes any unrecorded transactions needed to link it back to the block chain.
|
||||||
|
@ -843,7 +854,8 @@ public:
|
||||||
|
|
||||||
std::map<libzcash::SproutPaymentAddress, CKeyMetadata> mapSproutZKeyMetadata;
|
std::map<libzcash::SproutPaymentAddress, CKeyMetadata> mapSproutZKeyMetadata;
|
||||||
std::map<libzcash::SaplingIncomingViewingKey, CKeyMetadata> mapSaplingZKeyMetadata;
|
std::map<libzcash::SaplingIncomingViewingKey, CKeyMetadata> mapSaplingZKeyMetadata;
|
||||||
std::map<libzcash::UFVKId, ZcashdUnifiedSpendingKeyMetadata> mapUnifiedKeyMetadata;
|
std::map<std::pair<libzcash::SeedFingerprint, libzcash::AccountId>, ZcashdUnifiedSpendingKeyMetadata> mapUnifiedKeyMetadata;
|
||||||
|
std::map<libzcash::UFVKId, std::map<libzcash::diversifier_index_t, std::set<libzcash::ReceiverType>>> mapUnifiedAddressMetadata;
|
||||||
|
|
||||||
typedef std::map<unsigned int, CMasterKey> MasterKeyMap;
|
typedef std::map<unsigned int, CMasterKey> MasterKeyMap;
|
||||||
MasterKeyMap mapMasterKeys;
|
MasterKeyMap mapMasterKeys;
|
||||||
|
@ -1129,10 +1141,22 @@ public:
|
||||||
std::optional<std::pair<libzcash::ZcashdUnifiedSpendingKey, ZcashdUnifiedSpendingKeyMetadata>>
|
std::optional<std::pair<libzcash::ZcashdUnifiedSpendingKey, ZcashdUnifiedSpendingKeyMetadata>>
|
||||||
GenerateUnifiedSpendingKeyForAccount(libzcash::AccountId accountId);
|
GenerateUnifiedSpendingKeyForAccount(libzcash::AccountId accountId);
|
||||||
|
|
||||||
bool AddUnifiedFullViewingKey(const libzcash::UnifiedFullViewingKey &ufvk);
|
//! Retrieves the UFVK derived from the wallet's mnemonic seed for the specified account.
|
||||||
bool LoadUnifiedFullViewingKey(const libzcash::UnifiedFullViewingKey &key);
|
std::optional<std::pair<libzcash::UFVKId, libzcash::ZcashdUnifiedFullViewingKey>>
|
||||||
|
GetUnifiedFullViewingKeyByAccount(libzcash::AccountId account);
|
||||||
|
|
||||||
void LoadUnifiedKeyMetadata(const ZcashdUnifiedSpendingKeyMetadata &meta);
|
//! Generate a new unified address for the specified account, diversifier, and
|
||||||
|
//! set of receiver types.
|
||||||
|
UAGenerationResult GenerateUnifiedAddress(
|
||||||
|
const libzcash::AccountId& accountId,
|
||||||
|
const libzcash::diversifier_index_t& j,
|
||||||
|
const std::set<libzcash::ReceiverType>& receivers);
|
||||||
|
|
||||||
|
bool AddUnifiedFullViewingKey(const libzcash::UnifiedFullViewingKey &ufvk);
|
||||||
|
bool LoadUnifiedFullViewingKey(const libzcash::UnifiedFullViewingKey &ufvk);
|
||||||
|
|
||||||
|
void LoadUnifiedKeyMetadata(const ZcashdUnifiedSpendingKeyMetadata &skmeta);
|
||||||
|
bool LoadUnifiedAddressMetadata(const ZcashdUnifiedAddressMetadata &addrmeta);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Increment the next transaction order id
|
* Increment the next transaction order id
|
||||||
|
|
|
@ -235,6 +235,13 @@ bool CWalletDB::WriteUnifiedFullViewingKey(const libzcash::UnifiedFullViewingKey
|
||||||
return Write(std::make_pair(std::string("unifiedfvk"), ufvkId), ufvk.Encode(Params()));
|
return Write(std::make_pair(std::string("unifiedfvk"), ufvkId), ufvk.Encode(Params()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CWalletDB::WriteUnifiedAddressMetadata(const ZcashdUnifiedAddressMetadata& addrmeta)
|
||||||
|
{
|
||||||
|
nWalletDBUpdateCounter++;
|
||||||
|
auto ufvkId = addrmeta.GetKeyID();
|
||||||
|
return Write(std::make_pair(std::string("unifiedaddrmeta"), ufvkId), addrmeta);
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
|
@ -684,6 +691,11 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
|
||||||
auto keymeta = ZcashdUnifiedSpendingKeyMetadata::Read(ssValue);
|
auto keymeta = ZcashdUnifiedSpendingKeyMetadata::Read(ssValue);
|
||||||
pwallet->LoadUnifiedKeyMetadata(keymeta);
|
pwallet->LoadUnifiedKeyMetadata(keymeta);
|
||||||
}
|
}
|
||||||
|
else if (strType == "unifiedaddrmeta")
|
||||||
|
{
|
||||||
|
auto keymeta = ZcashdUnifiedAddressMetadata::Read(ssValue);
|
||||||
|
pwallet->LoadUnifiedAddressMetadata(keymeta);
|
||||||
|
}
|
||||||
else if (strType == "pool")
|
else if (strType == "pool")
|
||||||
{
|
{
|
||||||
int64_t nIndex;
|
int64_t nIndex;
|
||||||
|
|
|
@ -251,14 +251,14 @@ class ZcashdUnifiedAddressMetadata {
|
||||||
private:
|
private:
|
||||||
libzcash::UFVKId ufvkId;
|
libzcash::UFVKId ufvkId;
|
||||||
libzcash::diversifier_index_t diversifierIndex;
|
libzcash::diversifier_index_t diversifierIndex;
|
||||||
std::vector<libzcash::ReceiverType> receiverTypes;
|
std::set<libzcash::ReceiverType> receiverTypes;
|
||||||
|
|
||||||
ZcashdUnifiedAddressMetadata() {}
|
ZcashdUnifiedAddressMetadata() {}
|
||||||
public:
|
public:
|
||||||
ZcashdUnifiedAddressMetadata(
|
ZcashdUnifiedAddressMetadata(
|
||||||
libzcash::UFVKId ufvkId,
|
libzcash::UFVKId ufvkId,
|
||||||
libzcash::diversifier_index_t diversifierIndex,
|
libzcash::diversifier_index_t diversifierIndex,
|
||||||
std::vector<libzcash::ReceiverType> receiverTypes):
|
std::set<libzcash::ReceiverType> receiverTypes):
|
||||||
ufvkId(ufvkId), diversifierIndex(diversifierIndex), receiverTypes(receiverTypes) {}
|
ufvkId(ufvkId), diversifierIndex(diversifierIndex), receiverTypes(receiverTypes) {}
|
||||||
|
|
||||||
libzcash::UFVKId GetKeyID() const {
|
libzcash::UFVKId GetKeyID() const {
|
||||||
|
@ -267,7 +267,7 @@ public:
|
||||||
libzcash::diversifier_index_t GetDiversifierIndex() const {
|
libzcash::diversifier_index_t GetDiversifierIndex() const {
|
||||||
return diversifierIndex;
|
return diversifierIndex;
|
||||||
}
|
}
|
||||||
const std::vector<libzcash::ReceiverType>& GetReceiverTypes() const {
|
const std::set<libzcash::ReceiverType>& GetReceiverTypes() const {
|
||||||
return receiverTypes;
|
return receiverTypes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -282,7 +282,7 @@ public:
|
||||||
READWRITE(serReceiverTypes);
|
READWRITE(serReceiverTypes);
|
||||||
receiverTypes.clear();
|
receiverTypes.clear();
|
||||||
for (ReceiverTypeSer r : serReceiverTypes)
|
for (ReceiverTypeSer r : serReceiverTypes)
|
||||||
receiverTypes.push_back(r.t);
|
receiverTypes.insert(r.t);
|
||||||
} else {
|
} else {
|
||||||
std::vector<ReceiverTypeSer> serReceiverTypes;
|
std::vector<ReceiverTypeSer> serReceiverTypes;
|
||||||
for (libzcash::ReceiverType r : receiverTypes)
|
for (libzcash::ReceiverType r : receiverTypes)
|
||||||
|
@ -381,6 +381,7 @@ public:
|
||||||
|
|
||||||
bool WriteUnifiedSpendingKeyMetadata(const ZcashdUnifiedSpendingKeyMetadata& keymeta);
|
bool WriteUnifiedSpendingKeyMetadata(const ZcashdUnifiedSpendingKeyMetadata& keymeta);
|
||||||
bool WriteUnifiedFullViewingKey(const libzcash::UnifiedFullViewingKey& ufvk);
|
bool WriteUnifiedFullViewingKey(const libzcash::UnifiedFullViewingKey& ufvk);
|
||||||
|
bool WriteUnifiedAddressMetadata(const ZcashdUnifiedAddressMetadata& addrmeta);
|
||||||
|
|
||||||
static void IncrementUpdateCounter();
|
static void IncrementUpdateCounter();
|
||||||
static unsigned int GetUpdateCounter();
|
static unsigned int GetUpdateCounter();
|
||||||
|
|
|
@ -12,6 +12,14 @@ using namespace libzcash;
|
||||||
// Unified Keys
|
// Unified Keys
|
||||||
//
|
//
|
||||||
|
|
||||||
|
bool libzcash::HasShielded(const std::set<ReceiverType>& receiverTypes) {
|
||||||
|
auto has_shielded = [](ReceiverType r) {
|
||||||
|
// TODO: update this as support for new protocols is added.
|
||||||
|
return r == ReceiverType::Sapling;
|
||||||
|
};
|
||||||
|
return std::find_if(receiverTypes.begin(), receiverTypes.end(), has_shielded) != receiverTypes.end();
|
||||||
|
}
|
||||||
|
|
||||||
std::optional<ZcashdUnifiedSpendingKey> ZcashdUnifiedSpendingKey::ForAccount(
|
std::optional<ZcashdUnifiedSpendingKey> ZcashdUnifiedSpendingKey::ForAccount(
|
||||||
const HDSeed& seed,
|
const HDSeed& seed,
|
||||||
uint32_t bip44CoinType,
|
uint32_t bip44CoinType,
|
||||||
|
@ -63,10 +71,17 @@ ZcashdUnifiedFullViewingKey ZcashdUnifiedFullViewingKey::FromUnifiedFullViewingK
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<UnifiedAddress> ZcashdUnifiedFullViewingKey::Address(diversifier_index_t j) const {
|
std::optional<UnifiedAddress> ZcashdUnifiedFullViewingKey::Address(
|
||||||
UnifiedAddress ua;
|
const diversifier_index_t& j,
|
||||||
|
const std::set<ReceiverType>& receiverTypes) const
|
||||||
|
{
|
||||||
|
if (!HasShielded(receiverTypes)) {
|
||||||
|
throw std::runtime_error("Unified addresses must include a shielded receiver.");
|
||||||
|
}
|
||||||
|
|
||||||
if (saplingKey.has_value()) {
|
UnifiedAddress ua;
|
||||||
|
if (saplingKey.has_value() &&
|
||||||
|
std::find(receiverTypes.begin(), receiverTypes.end(), ReceiverType::Sapling) != receiverTypes.end()) {
|
||||||
auto saplingAddress = saplingKey.value().Address(j);
|
auto saplingAddress = saplingKey.value().Address(j);
|
||||||
if (saplingAddress.has_value()) {
|
if (saplingAddress.has_value()) {
|
||||||
ua.AddReceiver(saplingAddress.value());
|
ua.AddReceiver(saplingAddress.value());
|
||||||
|
@ -75,7 +90,8 @@ std::optional<UnifiedAddress> ZcashdUnifiedFullViewingKey::Address(diversifier_i
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (transparentKey.has_value()) {
|
if (transparentKey.has_value() &&
|
||||||
|
std::find(receiverTypes.begin(), receiverTypes.end(), ReceiverType::P2PKH) != receiverTypes.end()) {
|
||||||
const auto& tkey = transparentKey.value();
|
const auto& tkey = transparentKey.value();
|
||||||
auto childIndex = j.ToTransparentChildIndex();
|
auto childIndex = j.ToTransparentChildIndex();
|
||||||
if (!childIndex.has_value()) return std::nullopt;
|
if (!childIndex.has_value()) return std::nullopt;
|
||||||
|
@ -98,12 +114,20 @@ std::optional<UnifiedAddress> ZcashdUnifiedFullViewingKey::Address(diversifier_i
|
||||||
return ua;
|
return ua;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<UnifiedAddress, diversifier_index_t> ZcashdUnifiedFullViewingKey::FindAddress(diversifier_index_t j) const {
|
std::pair<UnifiedAddress, diversifier_index_t> ZcashdUnifiedFullViewingKey::FindAddress(
|
||||||
auto addr = Address(j);
|
const diversifier_index_t& j,
|
||||||
|
const std::set<ReceiverType>& receiverTypes) const {
|
||||||
|
diversifier_index_t j0(j);
|
||||||
|
auto addr = Address(j0, receiverTypes);
|
||||||
while (!addr.has_value()) {
|
while (!addr.has_value()) {
|
||||||
if (!j.increment())
|
if (!j0.increment())
|
||||||
throw std::runtime_error(std::string(__func__) + ": diversifier index overflow.");;
|
throw std::runtime_error(std::string(__func__) + ": diversifier index overflow.");;
|
||||||
addr = Address(j);
|
addr = Address(j0, receiverTypes);
|
||||||
}
|
}
|
||||||
return std::make_pair(addr.value(), j);
|
return std::make_pair(addr.value(), j0);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::pair<UnifiedAddress, diversifier_index_t> ZcashdUnifiedFullViewingKey::FindAddress(
|
||||||
|
const diversifier_index_t& j) const {
|
||||||
|
return FindAddress(j, {ReceiverType::P2PKH, ReceiverType::Sapling, ReceiverType::Orchard});
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,12 @@ enum class ReceiverType: uint32_t {
|
||||||
Orchard = 0x03
|
Orchard = 0x03
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test whether the specified list of receiver types contains a
|
||||||
|
* shielded receiver type
|
||||||
|
*/
|
||||||
|
bool HasShielded(const std::set<ReceiverType>& receiverTypes);
|
||||||
|
|
||||||
class ZcashdUnifiedSpendingKey;
|
class ZcashdUnifiedSpendingKey;
|
||||||
|
|
||||||
// prototypes for the classes handling ZIP-316 encoding (in Address.hpp)
|
// prototypes for the classes handling ZIP-316 encoding (in Address.hpp)
|
||||||
|
@ -51,9 +57,33 @@ public:
|
||||||
return saplingKey;
|
return saplingKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<UnifiedAddress> Address(diversifier_index_t j) const;
|
/**
|
||||||
|
* Creates a new unified address having the specified receiver types, at the specified
|
||||||
|
* diversifier index, unless the diversifer index would generate an invalid receiver.
|
||||||
|
* Returns `std::nullopt` if the diversifier index does not produce a valid receiver
|
||||||
|
* for one or more of the specified receiver types; under this circumstance, the caller
|
||||||
|
* should usually try successive diversifier indices until the operation returns a
|
||||||
|
* non-null value.
|
||||||
|
*
|
||||||
|
* This method will throw if `receiverTypes` does not include a shielded receiver type.
|
||||||
|
*/
|
||||||
|
std::optional<UnifiedAddress> Address(
|
||||||
|
const diversifier_index_t& j,
|
||||||
|
const std::set<ReceiverType>& receiverTypes) const;
|
||||||
|
|
||||||
std::pair<UnifiedAddress, diversifier_index_t> FindAddress(diversifier_index_t j) const;
|
/**
|
||||||
|
* Find the smallest diversifier index >= `j` such that it generates a valid
|
||||||
|
* unified address according to the conditions specified in the documentation
|
||||||
|
* for the `Address` method above, and returns the newly created address along
|
||||||
|
* with the diversifier index used to produce it.
|
||||||
|
*
|
||||||
|
* This method will throw if `receiverTypes` does not include a shielded receiver type.
|
||||||
|
*/
|
||||||
|
std::pair<UnifiedAddress, diversifier_index_t> FindAddress(
|
||||||
|
const diversifier_index_t& j,
|
||||||
|
const std::set<ReceiverType>& receiverTypes) const;
|
||||||
|
|
||||||
|
std::pair<UnifiedAddress, diversifier_index_t> FindAddress(const diversifier_index_t& j) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in New Issue