Add unified key components to the transparent & Sapling wallet parts.
This commit is contained in:
parent
24ff7b36ec
commit
6d36921b94
|
@ -79,6 +79,7 @@ static SaplingPaymentAddress DefaultSaplingAddress(CWallet* pwallet) {
|
||||||
auto usk = pwallet->GenerateUnifiedSpendingKeyForAccount(0);
|
auto usk = pwallet->GenerateUnifiedSpendingKeyForAccount(0);
|
||||||
|
|
||||||
return usk.value()
|
return usk.value()
|
||||||
|
.first
|
||||||
.ToFullViewingKey()
|
.ToFullViewingKey()
|
||||||
.GetSaplingKey().value()
|
.GetSaplingKey().value()
|
||||||
.FindAddress(libzcash::diversifier_index_t(0)).first;
|
.FindAddress(libzcash::diversifier_index_t(0)).first;
|
||||||
|
|
|
@ -172,7 +172,6 @@ std::pair<SaplingExtendedSpendingKey, bool> CWallet::GenerateLegacySaplingZKey(u
|
||||||
} else {
|
} else {
|
||||||
return std::make_pair(xsk.first, false);
|
return std::make_pair(xsk.first, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add spending key to keystore
|
// Add spending key to keystore
|
||||||
|
@ -288,14 +287,26 @@ CPubKey CWallet::GenerateNewKey()
|
||||||
// if we did not successfully generate a key, try again.
|
// if we did not successfully generate a key, try again.
|
||||||
} while (!extKey.has_value());
|
} 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();
|
CPubKey pubkey = secret.GetPubKey();
|
||||||
assert(secret.VerifyPubKey(pubkey));
|
assert(secret.VerifyPubKey(pubkey));
|
||||||
|
|
||||||
// Create new metadata
|
// Create new metadata
|
||||||
CKeyMetadata keyMeta(GetTime());
|
CKeyMetadata keyMeta(GetTime());
|
||||||
keyMeta.hdKeypath = extKey.value().second;
|
keyMeta.hdKeypath = extSecret.second;
|
||||||
keyMeta.seedFp = seed.Fingerprint();
|
keyMeta.seedFp = seedFingerprint;
|
||||||
mapKeyMetadata[pubkey.GetID()] = keyMeta;
|
mapKeyMetadata[pubkey.GetID()] = keyMeta;
|
||||||
if (nTimeFirstKey == 0 || keyMeta.nCreateTime < nTimeFirstKey)
|
if (nTimeFirstKey == 0 || keyMeta.nCreateTime < nTimeFirstKey)
|
||||||
nTimeFirstKey = keyMeta.nCreateTime;
|
nTimeFirstKey = keyMeta.nCreateTime;
|
||||||
|
@ -303,11 +314,6 @@ CPubKey CWallet::GenerateNewKey()
|
||||||
if (!AddKeyPubKey(secret, pubkey))
|
if (!AddKeyPubKey(secret, pubkey))
|
||||||
throw std::runtime_error("CWallet::GenerateNewKey(): AddKey failed");
|
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;
|
return pubkey;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -407,7 +413,7 @@ bool CWallet::AddCryptedSaplingSpendingKey(const libzcash::SaplingExtendedFullVi
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ZcashdUnifiedSpendingKey CWallet::GenerateNewUnifiedSpendingKey() {
|
std::pair<ZcashdUnifiedSpendingKey, ZcashdUnifiedKeyMetadata> CWallet::GenerateNewUnifiedSpendingKey() {
|
||||||
AssertLockHeld(cs_wallet);
|
AssertLockHeld(cs_wallet);
|
||||||
|
|
||||||
if (!mnemonicHDChain.has_value()) {
|
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();
|
auto seed = GetMnemonicSeed();
|
||||||
if (!seed.has_value()) {
|
if (!seed.has_value()) {
|
||||||
throw std::runtime_error(std::string(__func__) + ": Wallet has no mnemonic HD seed.");
|
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);
|
auto usk = ZcashdUnifiedSpendingKey::ForAccount(seed.value(), BIP44CoinType(), accountId);
|
||||||
if (usk.has_value()) {
|
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 {
|
} else {
|
||||||
return std::nullopt;
|
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)
|
void CWallet::LoadKeyMetadata(const CPubKey &pubkey, const CKeyMetadata &meta)
|
||||||
{
|
{
|
||||||
AssertLockHeld(cs_wallet); // mapKeyMetadata
|
AssertLockHeld(cs_wallet); // mapKeyMetadata
|
||||||
|
@ -5542,7 +5595,7 @@ KeyAddResult AddSpendingKeyToWallet::operator()(const libzcash::SaplingExtendedS
|
||||||
if (m_wallet->HaveSaplingSpendingKey(extfvk)) {
|
if (m_wallet->HaveSaplingSpendingKey(extfvk)) {
|
||||||
return KeyAlreadyExists;
|
return KeyAlreadyExists;
|
||||||
} else {
|
} else {
|
||||||
if (!m_wallet-> AddSaplingZKey(sk)) {
|
if (!m_wallet->AddSaplingZKey(sk)) {
|
||||||
return KeyNotAdded;
|
return KeyNotAdded;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5556,7 +5609,7 @@ KeyAddResult AddSpendingKeyToWallet::operator()(const libzcash::SaplingExtendedS
|
||||||
if (hdKeypath.has_value()) {
|
if (hdKeypath.has_value()) {
|
||||||
m_wallet->mapSaplingZKeyMetadata[ivk].hdKeypath = hdKeypath.value();
|
m_wallet->mapSaplingZKeyMetadata[ivk].hdKeypath = hdKeypath.value();
|
||||||
}
|
}
|
||||||
if (seedFpStr) {
|
if (seedFpStr.has_value()) {
|
||||||
uint256 seedFp;
|
uint256 seedFp;
|
||||||
seedFp.SetHex(seedFpStr.value());
|
seedFp.SetHex(seedFpStr.value());
|
||||||
m_wallet->mapSaplingZKeyMetadata[ivk].seedFp = seedFp;
|
m_wallet->mapSaplingZKeyMetadata[ivk].seedFp = seedFp;
|
||||||
|
|
|
@ -803,6 +803,9 @@ private:
|
||||||
void SyncMetaData(std::pair<typename TxSpendMap<T>::iterator, typename TxSpendMap<T>::iterator>);
|
void SyncMetaData(std::pair<typename TxSpendMap<T>::iterator, typename TxSpendMap<T>::iterator>);
|
||||||
void ChainTipAdded(const CBlockIndex *pindex, const CBlock *pblock, SproutMerkleTree sproutTree, SaplingMerkleTree saplingTree);
|
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:
|
protected:
|
||||||
bool UpdatedNoteData(const CWalletTx& wtxIn, CWalletTx& wtx);
|
bool UpdatedNoteData(const CWalletTx& wtxIn, CWalletTx& wtx);
|
||||||
void MarkAffectedTransactionsDirty(const CTransaction& tx);
|
void MarkAffectedTransactionsDirty(const CTransaction& tx);
|
||||||
|
@ -830,6 +833,7 @@ public:
|
||||||
std::map<CKeyID, CKeyMetadata> mapKeyMetadata;
|
std::map<CKeyID, CKeyMetadata> mapKeyMetadata;
|
||||||
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<std::pair<libzcash::SeedFingerprint, libzcash::AccountId>, libzcash::ZcashdUnifiedKeyMetadata> mapUnifiedKeyMetadata;
|
||||||
|
|
||||||
typedef std::map<unsigned int, CMasterKey> MasterKeyMap;
|
typedef std::map<unsigned int, CMasterKey> MasterKeyMap;
|
||||||
MasterKeyMap mapMasterKeys;
|
MasterKeyMap mapMasterKeys;
|
||||||
|
@ -1096,11 +1100,27 @@ public:
|
||||||
bool LoadCryptedSaplingZKey(const libzcash::SaplingExtendedFullViewingKey &extfvk,
|
bool LoadCryptedSaplingZKey(const libzcash::SaplingExtendedFullViewingKey &extfvk,
|
||||||
const std::vector<unsigned char> &vchCryptedSecret);
|
const std::vector<unsigned char> &vchCryptedSecret);
|
||||||
|
|
||||||
/**
|
//
|
||||||
* Unified keys & addresses
|
// Unified keys & addresses
|
||||||
*/
|
//
|
||||||
libzcash::ZcashdUnifiedSpendingKey GenerateNewUnifiedSpendingKey();
|
|
||||||
std::optional<libzcash::ZcashdUnifiedSpendingKey> GenerateUnifiedSpendingKeyForAccount(libzcash::AccountId accountId);
|
//! 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
|
* Increment the next transaction order id
|
||||||
|
|
|
@ -169,6 +169,7 @@ bool CWalletDB::WriteZKey(const libzcash::SproutPaymentAddress& addr, const libz
|
||||||
// pair is: tuple_key("zkey", paymentaddress) --> secretkey
|
// pair is: tuple_key("zkey", paymentaddress) --> secretkey
|
||||||
return Write(std::make_pair(std::string("zkey"), addr), key, false);
|
return Write(std::make_pair(std::string("zkey"), addr), key, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CWalletDB::WriteSaplingZKey(const libzcash::SaplingIncomingViewingKey &ivk,
|
bool CWalletDB::WriteSaplingZKey(const libzcash::SaplingIncomingViewingKey &ivk,
|
||||||
const libzcash::SaplingExtendedSpendingKey &key,
|
const libzcash::SaplingExtendedSpendingKey &key,
|
||||||
const CKeyMetadata &keyMeta)
|
const CKeyMetadata &keyMeta)
|
||||||
|
|
|
@ -20,6 +20,30 @@ enum class ReceiverType: uint32_t {
|
||||||
Orchard = 0x03
|
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 ZcashdUnifiedSpendingKey;
|
||||||
class ZcashdUnifiedFullViewingKey;
|
class ZcashdUnifiedFullViewingKey;
|
||||||
|
|
||||||
|
@ -30,23 +54,56 @@ class UnifiedFullViewingKey;
|
||||||
|
|
||||||
class ZcashdUnifiedKeyMetadata {
|
class ZcashdUnifiedKeyMetadata {
|
||||||
private:
|
private:
|
||||||
uint256 seedFp;
|
SeedFingerprint seedFp;
|
||||||
uint32_t bip44CoinType;
|
uint32_t bip44CoinType;
|
||||||
libzcash::AccountId accountId;
|
libzcash::AccountId accountId;
|
||||||
std::vector<ReceiverType> receiverTypes;
|
std::vector<libzcash::ReceiverType> receiverTypes;
|
||||||
|
|
||||||
|
ZcashdUnifiedKeyMetadata() {}
|
||||||
public:
|
public:
|
||||||
ZcashdUnifiedKeyMetadata(
|
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) {}
|
seedFp(seedFp), bip44CoinType(bip44CoinType), accountId(accountId), receiverTypes(receiverTypes) {}
|
||||||
|
|
||||||
const uint256& GetSeedFingerprint() const {
|
const SeedFingerprint& GetSeedFingerprint() const {
|
||||||
return seedFp;
|
return seedFp;
|
||||||
}
|
}
|
||||||
|
libzcash::AccountId GetAccountId() const {
|
||||||
|
return accountId;
|
||||||
|
}
|
||||||
const std::vector<ReceiverType>& GetReceiverTypes() const {
|
const std::vector<ReceiverType>& GetReceiverTypes() const {
|
||||||
return receiverTypes;
|
return receiverTypes;
|
||||||
}
|
}
|
||||||
std::optional<HDKeyPath> TransparentKeyPath() const;
|
std::optional<HDKeyPath> TransparentKeyPath() const;
|
||||||
std::optional<HDKeyPath> SaplingKeyPath() 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;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -62,6 +62,7 @@ uint256 ovkForShieldingFromTaddr(HDSeed& seed);
|
||||||
|
|
||||||
namespace libzcash {
|
namespace libzcash {
|
||||||
|
|
||||||
|
typedef uint256 SeedFingerprint;
|
||||||
typedef uint32_t AccountId;
|
typedef uint32_t AccountId;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in New Issue