Auto merge of #3392 - arcalinea:sapling_z_importexport_keys, r=bitcartel
Add Sapling support to z_importkey, z_exportkey Add Sapling support to `z_importkey` and `z_exportkey`
This commit is contained in:
@@ -564,7 +564,7 @@ BOOST_AUTO_TEST_CASE(rpc_wallet_z_importexport)
|
|||||||
|
|
||||||
// verify import and export key
|
// verify import and export key
|
||||||
for (int i = 0; i < n1; i++) {
|
for (int i = 0; i < n1; i++) {
|
||||||
// create a random key locally
|
// create a random Sprout key locally
|
||||||
auto testSpendingKey = libzcash::SproutSpendingKey::random();
|
auto testSpendingKey = libzcash::SproutSpendingKey::random();
|
||||||
auto testPaymentAddress = testSpendingKey.address();
|
auto testPaymentAddress = testSpendingKey.address();
|
||||||
std::string testAddr = EncodePaymentAddress(testPaymentAddress);
|
std::string testAddr = EncodePaymentAddress(testPaymentAddress);
|
||||||
@@ -572,6 +572,15 @@ BOOST_AUTO_TEST_CASE(rpc_wallet_z_importexport)
|
|||||||
BOOST_CHECK_NO_THROW(CallRPC(string("z_importkey ") + testKey));
|
BOOST_CHECK_NO_THROW(CallRPC(string("z_importkey ") + testKey));
|
||||||
BOOST_CHECK_NO_THROW(retValue = CallRPC(string("z_exportkey ") + testAddr));
|
BOOST_CHECK_NO_THROW(retValue = CallRPC(string("z_exportkey ") + testAddr));
|
||||||
BOOST_CHECK_EQUAL(retValue.get_str(), testKey);
|
BOOST_CHECK_EQUAL(retValue.get_str(), testKey);
|
||||||
|
|
||||||
|
// create a random Sapling key locally
|
||||||
|
auto testSaplingSpendingKey = libzcash::SaplingSpendingKey::random();
|
||||||
|
auto testSaplingPaymentAddress = testSaplingSpendingKey.default_address();
|
||||||
|
std::string testSaplingAddr = EncodePaymentAddress(testSaplingPaymentAddress);
|
||||||
|
std::string testSaplingKey = EncodeSpendingKey(testSaplingSpendingKey);
|
||||||
|
BOOST_CHECK_NO_THROW(CallRPC(string("z_importkey ") + testSaplingKey));
|
||||||
|
BOOST_CHECK_NO_THROW(retValue = CallRPC(string("z_exportkey ") + testSaplingAddr));
|
||||||
|
BOOST_CHECK_EQUAL(retValue.get_str(), testSaplingKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify we can list the keys imported
|
// Verify we can list the keys imported
|
||||||
|
|||||||
@@ -550,6 +550,58 @@ UniValue dumpwallet_impl(const UniValue& params, bool fHelp, bool fDumpZKeys)
|
|||||||
return exportfilepath.string();
|
return exportfilepath.string();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class AddSpendingKeyToWallet : public boost::static_visitor<bool>
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
CWallet *m_wallet;
|
||||||
|
public:
|
||||||
|
AddSpendingKeyToWallet(CWallet *wallet) : m_wallet(wallet) {}
|
||||||
|
|
||||||
|
bool operator()(const libzcash::SproutSpendingKey &sk) const {
|
||||||
|
auto addr = sk.address();
|
||||||
|
// Don't throw error in case a key is already there
|
||||||
|
if (m_wallet->HaveSpendingKey(addr)) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
m_wallet->MarkDirty();
|
||||||
|
|
||||||
|
if (!m_wallet-> AddZKey(sk)) {
|
||||||
|
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding spending key to wallet");
|
||||||
|
}
|
||||||
|
|
||||||
|
m_wallet->mapZKeyMetadata[addr].nCreateTime = 1;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator()(const libzcash::SaplingSpendingKey &sk) const {
|
||||||
|
auto fvk = sk.full_viewing_key();
|
||||||
|
auto addr = sk.default_address();
|
||||||
|
{
|
||||||
|
// Don't throw error in case a key is already there
|
||||||
|
if (m_wallet->HaveSaplingSpendingKey(fvk)) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
m_wallet->MarkDirty();
|
||||||
|
|
||||||
|
if (!m_wallet-> AddSaplingZKey(sk)) {
|
||||||
|
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding spending key to wallet");
|
||||||
|
}
|
||||||
|
|
||||||
|
m_wallet->mapSaplingZKeyMetadata[addr].nCreateTime = 1;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator()(const libzcash::InvalidEncoding& no) const {
|
||||||
|
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid spending key");
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
UniValue z_importkey(const UniValue& params, bool fHelp)
|
UniValue z_importkey(const UniValue& params, bool fHelp)
|
||||||
{
|
{
|
||||||
@@ -620,33 +672,19 @@ UniValue z_importkey(const UniValue& params, bool fHelp)
|
|||||||
if (!IsValidSpendingKey(spendingkey)) {
|
if (!IsValidSpendingKey(spendingkey)) {
|
||||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid spending key");
|
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid spending key");
|
||||||
}
|
}
|
||||||
// TODO: Add Sapling support. For now, ensure we can freely convert.
|
|
||||||
assert(boost::get<libzcash::SproutSpendingKey>(&spendingkey) != nullptr);
|
// Sapling support
|
||||||
auto key = boost::get<libzcash::SproutSpendingKey>(spendingkey);
|
auto keyAlreadyExists = boost::apply_visitor(AddSpendingKeyToWallet(pwalletMain), spendingkey);
|
||||||
auto addr = key.address();
|
if (keyAlreadyExists && fIgnoreExistingKey) {
|
||||||
|
return NullUniValue;
|
||||||
{
|
}
|
||||||
// Don't throw error in case a key is already there
|
|
||||||
if (pwalletMain->HaveSpendingKey(addr)) {
|
// whenever a key is imported, we need to scan the whole chain
|
||||||
if (fIgnoreExistingKey) {
|
pwalletMain->nTimeFirstKey = 1; // 0 would be considered 'no value'
|
||||||
return NullUniValue;
|
|
||||||
}
|
// We want to scan for transactions and notes
|
||||||
} else {
|
if (fRescan) {
|
||||||
pwalletMain->MarkDirty();
|
pwalletMain->ScanForWalletTransactions(chainActive[nRescanHeight], true);
|
||||||
|
|
||||||
if (!pwalletMain-> AddZKey(key))
|
|
||||||
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding spending key to wallet");
|
|
||||||
|
|
||||||
pwalletMain->mapZKeyMetadata[addr].nCreateTime = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// whenever a key is imported, we need to scan the whole chain
|
|
||||||
pwalletMain->nTimeFirstKey = 1; // 0 would be considered 'no value'
|
|
||||||
|
|
||||||
// We want to scan for transactions and notes
|
|
||||||
if (fRescan) {
|
|
||||||
pwalletMain->ScanForWalletTransactions(chainActive[nRescanHeight], true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return NullUniValue;
|
return NullUniValue;
|
||||||
@@ -746,6 +784,41 @@ UniValue z_importviewingkey(const UniValue& params, bool fHelp)
|
|||||||
return NullUniValue;
|
return NullUniValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class GetSpendingKeyForPaymentAddress : public boost::static_visitor<libzcash::SpendingKey>
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
CWallet *m_wallet;
|
||||||
|
public:
|
||||||
|
GetSpendingKeyForPaymentAddress(CWallet *wallet) : m_wallet(wallet) {}
|
||||||
|
|
||||||
|
libzcash::SpendingKey operator()(const libzcash::SproutPaymentAddress &zaddr) const
|
||||||
|
{
|
||||||
|
libzcash::SproutSpendingKey k;
|
||||||
|
if (!pwalletMain->GetSpendingKey(zaddr, k)) {
|
||||||
|
throw JSONRPCError(RPC_WALLET_ERROR, "Wallet does not hold private zkey for this zaddr");
|
||||||
|
}
|
||||||
|
return k;
|
||||||
|
}
|
||||||
|
|
||||||
|
libzcash::SpendingKey operator()(const libzcash::SaplingPaymentAddress &zaddr) const
|
||||||
|
{
|
||||||
|
libzcash::SaplingIncomingViewingKey ivk;
|
||||||
|
libzcash::SaplingFullViewingKey fvk;
|
||||||
|
libzcash::SaplingSpendingKey sk;
|
||||||
|
|
||||||
|
if (!pwalletMain->GetSaplingIncomingViewingKey(zaddr, ivk) ||
|
||||||
|
!pwalletMain->GetSaplingFullViewingKey(ivk, fvk) ||
|
||||||
|
!pwalletMain->GetSaplingSpendingKey(fvk, sk)) {
|
||||||
|
throw JSONRPCError(RPC_WALLET_ERROR, "Wallet does not hold private zkey for this zaddr");
|
||||||
|
}
|
||||||
|
return sk;
|
||||||
|
}
|
||||||
|
|
||||||
|
libzcash::SpendingKey operator()(const libzcash::InvalidEncoding& no) const {
|
||||||
|
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid zaddr");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
UniValue z_exportkey(const UniValue& params, bool fHelp)
|
UniValue z_exportkey(const UniValue& params, bool fHelp)
|
||||||
{
|
{
|
||||||
if (!EnsureWalletIsAvailable(fHelp))
|
if (!EnsureWalletIsAvailable(fHelp))
|
||||||
@@ -776,15 +849,10 @@ UniValue z_exportkey(const UniValue& params, bool fHelp)
|
|||||||
if (!IsValidPaymentAddress(address)) {
|
if (!IsValidPaymentAddress(address)) {
|
||||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid zaddr");
|
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid zaddr");
|
||||||
}
|
}
|
||||||
// TODO: Add Sapling support. For now, ensure we can freely convert.
|
|
||||||
assert(boost::get<libzcash::SproutPaymentAddress>(&address) != nullptr);
|
|
||||||
auto addr = boost::get<libzcash::SproutPaymentAddress>(address);
|
|
||||||
|
|
||||||
libzcash::SproutSpendingKey k;
|
// Sapling support
|
||||||
if (!pwalletMain->GetSpendingKey(addr, k))
|
auto sk = boost::apply_visitor(GetSpendingKeyForPaymentAddress(pwalletMain), address);
|
||||||
throw JSONRPCError(RPC_WALLET_ERROR, "Wallet does not hold private zkey for this zaddr");
|
return EncodeSpendingKey(sk);
|
||||||
|
|
||||||
return EncodeSpendingKey(k);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
UniValue z_exportviewingkey(const UniValue& params, bool fHelp)
|
UniValue z_exportviewingkey(const UniValue& params, bool fHelp)
|
||||||
|
|||||||
Reference in New Issue
Block a user