Add unified key components to the transparent & Sapling wallet parts.

This commit is contained in:
Kris Nuttycombe 2021-11-22 16:47:59 -07:00
parent 24ff7b36ec
commit 6d36921b94
6 changed files with 157 additions and 24 deletions

View File

@ -79,6 +79,7 @@ static SaplingPaymentAddress DefaultSaplingAddress(CWallet* pwallet) {
auto usk = pwallet->GenerateUnifiedSpendingKeyForAccount(0);
return usk.value()
.first
.ToFullViewingKey()
.GetSaplingKey().value()
.FindAddress(libzcash::diversifier_index_t(0)).first;

View File

@ -172,7 +172,6 @@ std::pair<SaplingExtendedSpendingKey, bool> CWallet::GenerateLegacySaplingZKey(u
} else {
return std::make_pair(xsk.first, false);
}
}
// Add spending key to keystore
@ -288,14 +287,26 @@ CPubKey CWallet::GenerateNewKey()
// if we did not successfully generate a key, try again.
} while (!extKey.has_value());
CKey secret = extKey.value().first.key;
auto pubkey = AddKey(seed.Fingerprint(), extKey.value());
// Update the persisted chain information
if (fFileBacked && !CWalletDB(strWalletFile).WriteMnemonicHDChain(hdChain)) {
throw std::runtime_error("CWallet::GenerateNewKey(): Writing HD chain model failed");
}
return pubkey;
}
CPubKey CWallet::AddKey(const uint256& seedFingerprint, const std::pair<CExtKey, HDKeyPath>& extSecret)
{
CKey secret = extSecret.first.key;
CPubKey pubkey = secret.GetPubKey();
assert(secret.VerifyPubKey(pubkey));
// Create new metadata
CKeyMetadata keyMeta(GetTime());
keyMeta.hdKeypath = extKey.value().second;
keyMeta.seedFp = seed.Fingerprint();
keyMeta.hdKeypath = extSecret.second;
keyMeta.seedFp = seedFingerprint;
mapKeyMetadata[pubkey.GetID()] = keyMeta;
if (nTimeFirstKey == 0 || keyMeta.nCreateTime < nTimeFirstKey)
nTimeFirstKey = keyMeta.nCreateTime;
@ -303,11 +314,6 @@ CPubKey CWallet::GenerateNewKey()
if (!AddKeyPubKey(secret, pubkey))
throw std::runtime_error("CWallet::GenerateNewKey(): AddKey failed");
// Update the persisted chain information
if (fFileBacked && !CWalletDB(strWalletFile).WriteMnemonicHDChain(hdChain)) {
throw std::runtime_error("CWallet::GenerateNewKey(): Writing HD chain model failed");
}
return pubkey;
}
@ -407,7 +413,7 @@ bool CWallet::AddCryptedSaplingSpendingKey(const libzcash::SaplingExtendedFullVi
return false;
}
ZcashdUnifiedSpendingKey CWallet::GenerateNewUnifiedSpendingKey() {
std::pair<ZcashdUnifiedSpendingKey, ZcashdUnifiedKeyMetadata> CWallet::GenerateNewUnifiedSpendingKey() {
AssertLockHeld(cs_wallet);
if (!mnemonicHDChain.has_value()) {
@ -431,7 +437,8 @@ ZcashdUnifiedSpendingKey CWallet::GenerateNewUnifiedSpendingKey() {
}
}
std::optional<libzcash::ZcashdUnifiedSpendingKey> CWallet::GenerateUnifiedSpendingKeyForAccount(libzcash::AccountId accountId) {
std::optional<std::pair<libzcash::ZcashdUnifiedSpendingKey, libzcash::ZcashdUnifiedKeyMetadata>>
CWallet::GenerateUnifiedSpendingKeyForAccount(libzcash::AccountId accountId) {
auto seed = GetMnemonicSeed();
if (!seed.has_value()) {
throw std::runtime_error(std::string(__func__) + ": Wallet has no mnemonic HD seed.");
@ -439,14 +446,60 @@ std::optional<libzcash::ZcashdUnifiedSpendingKey> CWallet::GenerateUnifiedSpendi
auto usk = ZcashdUnifiedSpendingKey::ForAccount(seed.value(), BIP44CoinType(), accountId);
if (usk.has_value()) {
// TODO: Save the unified full viewing key & metadata to the wallet
if (!AddUnifiedSpendingKey(usk.value().first, usk.value().second)) {
throw std::runtime_error("CWallet::GenerateUnifiedSpendingKeyForAccount(): AddUnifiedSpendingKey failed.");
}
return usk.value().first;
return usk.value();
} else {
return std::nullopt;
}
}
// Add spending key to keystore
bool CWallet::AddUnifiedSpendingKey(
const libzcash::ZcashdUnifiedSpendingKey& sk,
const libzcash::ZcashdUnifiedKeyMetadata& metadata) {
AssertLockHeld(cs_wallet); // mapSaplingZKeyMetadata
auto ufvk = sk.ToFullViewingKey();
auto metaKey = std::make_pair(metadata.GetSeedFingerprint(), metadata.GetAccountId());
mapUnifiedKeyMetadata.insert({metaKey, metadata});
// Add Transparent component to the wallet
if (sk.GetTransparentKey().has_value()) {
AddKey(metadata.GetSeedFingerprint(),
std::make_pair(sk.GetTransparentKey().value(), metadata.TransparentKeyPath().value()));
}
// Add Sapling component to the wallet
auto addSpendingKey = AddSpendingKeyToWallet(
this, Params().GetConsensus(), GetTime(),
metadata.SaplingKeyPath(), metadata.GetSeedFingerprint().GetHex(), true);
if (sk.GetSaplingExtendedSpendingKey().has_value() &&
addSpendingKey(sk.GetSaplingExtendedSpendingKey().value()) == KeyNotAdded) {
// If adding the Sapling key to the wallet failed, abort the process.
return false;
}
if (!fFileBacked) {
return true;
}
if (!IsCrypted()) {
//return CWalletDB(strWalletFile).WriteUnifiedFullViewingKey(ufvk, metadata);
}
return true;
}
void CWallet::LoadUnifiedKeyMetadata(const libzcash::ZcashdUnifiedKeyMetadata &meta)
{
AssertLockHeld(cs_wallet); // mapUnifiedKeyMetadata
auto key = std::make_pair(meta.GetSeedFingerprint(), meta.GetAccountId());
mapUnifiedKeyMetadata.insert({key, meta});
}
void CWallet::LoadKeyMetadata(const CPubKey &pubkey, const CKeyMetadata &meta)
{
AssertLockHeld(cs_wallet); // mapKeyMetadata
@ -5542,7 +5595,7 @@ KeyAddResult AddSpendingKeyToWallet::operator()(const libzcash::SaplingExtendedS
if (m_wallet->HaveSaplingSpendingKey(extfvk)) {
return KeyAlreadyExists;
} else {
if (!m_wallet-> AddSaplingZKey(sk)) {
if (!m_wallet->AddSaplingZKey(sk)) {
return KeyNotAdded;
}
@ -5556,7 +5609,7 @@ KeyAddResult AddSpendingKeyToWallet::operator()(const libzcash::SaplingExtendedS
if (hdKeypath.has_value()) {
m_wallet->mapSaplingZKeyMetadata[ivk].hdKeypath = hdKeypath.value();
}
if (seedFpStr) {
if (seedFpStr.has_value()) {
uint256 seedFp;
seedFp.SetHex(seedFpStr.value());
m_wallet->mapSaplingZKeyMetadata[ivk].seedFp = seedFp;

View File

@ -803,6 +803,9 @@ private:
void SyncMetaData(std::pair<typename TxSpendMap<T>::iterator, typename TxSpendMap<T>::iterator>);
void ChainTipAdded(const CBlockIndex *pindex, const CBlock *pblock, SproutMerkleTree sproutTree, SaplingMerkleTree saplingTree);
/* Add an extended secret key to the wallet. Internal use only. */
CPubKey AddKey(const uint256& seedFingerprint, const std::pair<CExtKey, HDKeyPath>& extSecret);
protected:
bool UpdatedNoteData(const CWalletTx& wtxIn, CWalletTx& wtx);
void MarkAffectedTransactionsDirty(const CTransaction& tx);
@ -830,6 +833,7 @@ public:
std::map<CKeyID, CKeyMetadata> mapKeyMetadata;
std::map<libzcash::SproutPaymentAddress, CKeyMetadata> mapSproutZKeyMetadata;
std::map<libzcash::SaplingIncomingViewingKey, CKeyMetadata> mapSaplingZKeyMetadata;
std::map<std::pair<libzcash::SeedFingerprint, libzcash::AccountId>, libzcash::ZcashdUnifiedKeyMetadata> mapUnifiedKeyMetadata;
typedef std::map<unsigned int, CMasterKey> MasterKeyMap;
MasterKeyMap mapMasterKeys;
@ -1096,11 +1100,27 @@ public:
bool LoadCryptedSaplingZKey(const libzcash::SaplingExtendedFullViewingKey &extfvk,
const std::vector<unsigned char> &vchCryptedSecret);
/**
* Unified keys & addresses
*/
libzcash::ZcashdUnifiedSpendingKey GenerateNewUnifiedSpendingKey();
std::optional<libzcash::ZcashdUnifiedSpendingKey> GenerateUnifiedSpendingKeyForAccount(libzcash::AccountId accountId);
//
// Unified keys & addresses
//
//! Generate the unified spending key from the wallet's mnemonic seed
//! for the next unused account identifier.
std::pair<libzcash::ZcashdUnifiedSpendingKey, libzcash::ZcashdUnifiedKeyMetadata>
GenerateNewUnifiedSpendingKey();
//! Generate the next available unified spending key from the wallet's
//! mnemonic seed.
std::optional<std::pair<libzcash::ZcashdUnifiedSpendingKey, libzcash::ZcashdUnifiedKeyMetadata>>
GenerateUnifiedSpendingKeyForAccount(libzcash::AccountId accountId);
//! Add the specified unified spending key to the wallet with the provided key
//! metadata.
bool AddUnifiedSpendingKey(
const libzcash::ZcashdUnifiedSpendingKey& sk,
const libzcash::ZcashdUnifiedKeyMetadata& metadata);
void LoadUnifiedKeyMetadata(const libzcash::ZcashdUnifiedKeyMetadata &meta);
/**
* Increment the next transaction order id

View File

@ -169,6 +169,7 @@ bool CWalletDB::WriteZKey(const libzcash::SproutPaymentAddress& addr, const libz
// pair is: tuple_key("zkey", paymentaddress) --> secretkey
return Write(std::make_pair(std::string("zkey"), addr), key, false);
}
bool CWalletDB::WriteSaplingZKey(const libzcash::SaplingIncomingViewingKey &ivk,
const libzcash::SaplingExtendedSpendingKey &key,
const CKeyMetadata &keyMeta)

View File

@ -20,6 +20,30 @@ enum class ReceiverType: uint32_t {
Orchard = 0x03
};
class ZcashdUnifiedKeyMetadata;
// Serialization wrapper for reading and writing ReceiverType
// in CompactSize format.
class ReceiverTypeSer {
private:
ReceiverType t;
friend class ZcashdUnifiedKeyMetadata;
public:
ReceiverTypeSer() {} // for serialization only
ReceiverTypeSer(ReceiverType t): t(t) {}
template<typename Stream>
void Serialize(Stream &s) const {
WriteCompactSize<Stream>(s, (uint64_t) t);
}
template<typename Stream>
void Unserialize(Stream& s) {
t = (ReceiverType) ReadCompactSize<Stream>(s);
}
};
class ZcashdUnifiedSpendingKey;
class ZcashdUnifiedFullViewingKey;
@ -30,23 +54,56 @@ class UnifiedFullViewingKey;
class ZcashdUnifiedKeyMetadata {
private:
uint256 seedFp;
SeedFingerprint seedFp;
uint32_t bip44CoinType;
libzcash::AccountId accountId;
std::vector<ReceiverType> receiverTypes;
std::vector<libzcash::ReceiverType> receiverTypes;
ZcashdUnifiedKeyMetadata() {}
public:
ZcashdUnifiedKeyMetadata(
uint256 seedFp, uint32_t bip44CoinType, libzcash::AccountId accountId, std::vector<ReceiverType> receiverTypes):
SeedFingerprint seedFp, uint32_t bip44CoinType, libzcash::AccountId accountId, std::vector<ReceiverType> receiverTypes):
seedFp(seedFp), bip44CoinType(bip44CoinType), accountId(accountId), receiverTypes(receiverTypes) {}
const uint256& GetSeedFingerprint() const {
const SeedFingerprint& GetSeedFingerprint() const {
return seedFp;
}
libzcash::AccountId GetAccountId() const {
return accountId;
}
const std::vector<ReceiverType>& GetReceiverTypes() const {
return receiverTypes;
}
std::optional<HDKeyPath> TransparentKeyPath() const;
std::optional<HDKeyPath> SaplingKeyPath() const;
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(seedFp);
READWRITE(bip44CoinType);
READWRITE(accountId);
if (ser_action.ForRead()) {
std::vector<ReceiverTypeSer> serReceiverTypes;
READWRITE(serReceiverTypes);
receiverTypes.clear();
for (ReceiverTypeSer r : serReceiverTypes)
receiverTypes.push_back(r.t);
} else {
std::vector<ReceiverTypeSer> serReceiverTypes;
for (ReceiverType r : receiverTypes)
serReceiverTypes.push_back(ReceiverTypeSer(r));
READWRITE(serReceiverTypes);
}
}
template <typename Stream>
static ZcashdUnifiedKeyMetadata Read(Stream& stream) {
ZcashdUnifiedKeyMetadata meta;
stream >> meta;
return meta;
}
};
/**

View File

@ -62,6 +62,7 @@ uint256 ovkForShieldingFromTaddr(HDSeed& seed);
namespace libzcash {
typedef uint256 SeedFingerprint;
typedef uint32_t AccountId;
/**