Auto merge of #1208 - bitcartel:z8_rpc_keys, r=daira
RPC calls to manage zkey creation, management and backup Rebased on PR #1205 for keystore functionality. For #1197, implements: z_getnewaddress z_importkey z_exportkey For #1198, spending key support added to: z_exportwallet z_importwallet Example dump file containing zkeys: https://gist.github.com/bitcartel/d7013b30b19419c6a550bc5d6ff6cc47 Also adds: z_listaddresses Tests in: gtest/test_wallet_zkeys test/rpc_wallet_tests
This commit is contained in:
@@ -14,6 +14,7 @@ zcash_gtest_SOURCES = \
|
|||||||
gtest/test_merkletree.cpp \
|
gtest/test_merkletree.cpp \
|
||||||
gtest/test_circuit.cpp \
|
gtest/test_circuit.cpp \
|
||||||
gtest/test_txid.cpp \
|
gtest/test_txid.cpp \
|
||||||
|
gtest/test_wallet_zkeys.cpp \
|
||||||
gtest/test_libzcash_utils.cpp \
|
gtest/test_libzcash_utils.cpp \
|
||||||
gtest/test_proofs.cpp
|
gtest/test_proofs.cpp
|
||||||
|
|
||||||
|
|||||||
140
src/gtest/test_wallet_zkeys.cpp
Normal file
140
src/gtest/test_wallet_zkeys.cpp
Normal file
@@ -0,0 +1,140 @@
|
|||||||
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
#include "zcash/Address.hpp"
|
||||||
|
#include "wallet/wallet.h"
|
||||||
|
#include "wallet/walletdb.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
#include <boost/filesystem.hpp>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This test covers methods on CWallet
|
||||||
|
* GenerateNewZKey()
|
||||||
|
* AddZKey()
|
||||||
|
* LoadZKey()
|
||||||
|
* LoadZKeyMetadata()
|
||||||
|
*/
|
||||||
|
TEST(wallet_zkeys_tests, store_and_load_zkeys) {
|
||||||
|
SelectParams(CBaseChainParams::MAIN);
|
||||||
|
|
||||||
|
CWallet wallet;
|
||||||
|
|
||||||
|
// wallet should be empty
|
||||||
|
std::set<libzcash::PaymentAddress> addrs;
|
||||||
|
wallet.GetPaymentAddresses(addrs);
|
||||||
|
ASSERT_EQ(0, addrs.size());
|
||||||
|
|
||||||
|
// wallet should have one key
|
||||||
|
CZCPaymentAddress paymentAddress = wallet.GenerateNewZKey();
|
||||||
|
wallet.GetPaymentAddresses(addrs);
|
||||||
|
ASSERT_EQ(1, addrs.size());
|
||||||
|
|
||||||
|
// verify wallet has spending key for the address
|
||||||
|
auto addr = paymentAddress.Get();
|
||||||
|
ASSERT_TRUE(wallet.HaveSpendingKey(addr));
|
||||||
|
|
||||||
|
// manually add new spending key to wallet
|
||||||
|
auto sk = libzcash::SpendingKey::random();
|
||||||
|
ASSERT_TRUE(wallet.AddZKey(sk));
|
||||||
|
|
||||||
|
// verify wallet did add it
|
||||||
|
addr = sk.address();
|
||||||
|
ASSERT_TRUE(wallet.HaveSpendingKey(addr));
|
||||||
|
|
||||||
|
// verify spending key stored correctly
|
||||||
|
libzcash::SpendingKey keyOut;
|
||||||
|
wallet.GetSpendingKey(addr, keyOut);
|
||||||
|
ASSERT_EQ(sk, keyOut);
|
||||||
|
|
||||||
|
// verify there are two keys
|
||||||
|
wallet.GetPaymentAddresses(addrs);
|
||||||
|
ASSERT_EQ(2, addrs.size());
|
||||||
|
ASSERT_EQ(1, addrs.count(addr));
|
||||||
|
|
||||||
|
// Load a third key into the wallet
|
||||||
|
sk = libzcash::SpendingKey::random();
|
||||||
|
ASSERT_TRUE(wallet.LoadZKey(sk));
|
||||||
|
|
||||||
|
// attach metadata to this third key
|
||||||
|
addr = sk.address();
|
||||||
|
int64_t now = GetTime();
|
||||||
|
CKeyMetadata meta(now);
|
||||||
|
ASSERT_TRUE(wallet.LoadZKeyMetadata(addr, meta));
|
||||||
|
|
||||||
|
// check metadata is the same
|
||||||
|
CKeyMetadata m= wallet.mapZKeyMetadata[addr];
|
||||||
|
ASSERT_EQ(m.nCreateTime, now);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This test covers methods on CWalletDB
|
||||||
|
* WriteZKey()
|
||||||
|
*/
|
||||||
|
TEST(wallet_zkeys_tests, write_zkey_direct_to_db) {
|
||||||
|
SelectParams(CBaseChainParams::TESTNET);
|
||||||
|
|
||||||
|
// Get temporary and unique path for file.
|
||||||
|
// Note: / operator to append paths
|
||||||
|
boost::filesystem::path temp = boost::filesystem::temp_directory_path() /
|
||||||
|
boost::filesystem::unique_path();
|
||||||
|
const std::string path = temp.native();
|
||||||
|
|
||||||
|
bool fFirstRun;
|
||||||
|
CWallet wallet(path);
|
||||||
|
ASSERT_EQ(DB_LOAD_OK, wallet.LoadWallet(fFirstRun));
|
||||||
|
|
||||||
|
// No default CPubKey set
|
||||||
|
ASSERT_TRUE(fFirstRun);
|
||||||
|
|
||||||
|
// wallet should be empty
|
||||||
|
std::set<libzcash::PaymentAddress> addrs;
|
||||||
|
wallet.GetPaymentAddresses(addrs);
|
||||||
|
ASSERT_EQ(0, addrs.size());
|
||||||
|
|
||||||
|
// Add random key to the wallet
|
||||||
|
auto paymentAddress = wallet.GenerateNewZKey();
|
||||||
|
|
||||||
|
// wallet should have one key
|
||||||
|
wallet.GetPaymentAddresses(addrs);
|
||||||
|
ASSERT_EQ(1, addrs.size());
|
||||||
|
|
||||||
|
// create random key and add it to database directly, bypassing wallet
|
||||||
|
auto sk = libzcash::SpendingKey::random();
|
||||||
|
auto addr = sk.address();
|
||||||
|
int64_t now = GetTime();
|
||||||
|
CKeyMetadata meta(now);
|
||||||
|
CWalletDB db(path);
|
||||||
|
db.WriteZKey(addr, sk, meta);
|
||||||
|
|
||||||
|
// wallet should not be aware of key
|
||||||
|
ASSERT_FALSE(wallet.HaveSpendingKey(addr));
|
||||||
|
|
||||||
|
// wallet sees one key
|
||||||
|
wallet.GetPaymentAddresses(addrs);
|
||||||
|
ASSERT_EQ(1, addrs.size());
|
||||||
|
|
||||||
|
// wallet should have default metadata for addr with null createtime
|
||||||
|
CKeyMetadata m = wallet.mapZKeyMetadata[addr];
|
||||||
|
ASSERT_EQ(m.nCreateTime, 0);
|
||||||
|
ASSERT_NE(m.nCreateTime, now);
|
||||||
|
|
||||||
|
// load the wallet again
|
||||||
|
ASSERT_EQ(DB_LOAD_OK, wallet.LoadWallet(fFirstRun));
|
||||||
|
|
||||||
|
// wallet can now see the spending key
|
||||||
|
ASSERT_TRUE(wallet.HaveSpendingKey(addr));
|
||||||
|
|
||||||
|
// check key is the same
|
||||||
|
libzcash::SpendingKey keyOut;
|
||||||
|
wallet.GetSpendingKey(addr, keyOut);
|
||||||
|
ASSERT_EQ(sk, keyOut);
|
||||||
|
|
||||||
|
// wallet should have two keys
|
||||||
|
wallet.GetPaymentAddresses(addrs);
|
||||||
|
ASSERT_EQ(2, addrs.size());
|
||||||
|
|
||||||
|
// check metadata is now the same
|
||||||
|
m = wallet.mapZKeyMetadata[addr];
|
||||||
|
ASSERT_EQ(m.nCreateTime, now);
|
||||||
|
}
|
||||||
|
|
||||||
@@ -97,7 +97,8 @@ static const CRPCConvertParam vRPCConvertParams[] =
|
|||||||
{ "zcrawjoinsplit", 4 },
|
{ "zcrawjoinsplit", 4 },
|
||||||
{ "zcbenchmark", 1 },
|
{ "zcbenchmark", 1 },
|
||||||
{ "zcbenchmark", 2 },
|
{ "zcbenchmark", 2 },
|
||||||
{ "getblocksubsidy", 0}
|
{ "getblocksubsidy", 0},
|
||||||
|
{ "z_importkey", 1 }
|
||||||
};
|
};
|
||||||
|
|
||||||
class CRPCConvertTable
|
class CRPCConvertTable
|
||||||
|
|||||||
@@ -381,7 +381,13 @@ static const CRPCCommand vRPCCommands[] =
|
|||||||
{ "wallet", "zcrawkeygen", &zc_raw_keygen, true },
|
{ "wallet", "zcrawkeygen", &zc_raw_keygen, true },
|
||||||
{ "wallet", "zcrawjoinsplit", &zc_raw_joinsplit, true },
|
{ "wallet", "zcrawjoinsplit", &zc_raw_joinsplit, true },
|
||||||
{ "wallet", "zcrawreceive", &zc_raw_receive, true },
|
{ "wallet", "zcrawreceive", &zc_raw_receive, true },
|
||||||
{ "wallet", "zcsamplejoinsplit", &zc_sample_joinsplit, true }
|
{ "wallet", "zcsamplejoinsplit", &zc_sample_joinsplit, true },
|
||||||
|
{ "wallet", "z_getnewaddress", &z_getnewaddress, true },
|
||||||
|
{ "wallet", "z_listaddresses", &z_listaddresses, true },
|
||||||
|
{ "wallet", "z_exportkey", &z_exportkey, true },
|
||||||
|
{ "wallet", "z_importkey", &z_importkey, true },
|
||||||
|
{ "wallet", "z_exportwallet", &z_exportwallet, true },
|
||||||
|
{ "wallet", "z_importwallet", &z_importwallet, true }
|
||||||
#endif // ENABLE_WALLET
|
#endif // ENABLE_WALLET
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -243,6 +243,13 @@ extern json_spirit::Value reconsiderblock(const json_spirit::Array& params, bool
|
|||||||
|
|
||||||
extern json_spirit::Value getblocksubsidy(const json_spirit::Array& params, bool fHelp);
|
extern json_spirit::Value getblocksubsidy(const json_spirit::Array& params, bool fHelp);
|
||||||
|
|
||||||
|
extern json_spirit::Value z_exportkey(const json_spirit::Array& params, bool fHelp); // in rpcdump.cpp
|
||||||
|
extern json_spirit::Value z_importkey(const json_spirit::Array& params, bool fHelp); // in rpcdump.cpp
|
||||||
|
extern json_spirit::Value z_getnewaddress(const json_spirit::Array& params, bool fHelp); // in rpcwallet.cpp
|
||||||
|
extern json_spirit::Value z_listaddresses(const json_spirit::Array& params, bool fHelp); // in rpcwallet.cpp
|
||||||
|
extern json_spirit::Value z_exportwallet(const json_spirit::Array& params, bool fHelp); // in rpcdump.cpp
|
||||||
|
extern json_spirit::Value z_importwallet(const json_spirit::Array& params, bool fHelp); // in rpcdump.cpp
|
||||||
|
|
||||||
// in rest.cpp
|
// in rest.cpp
|
||||||
extern bool HTTPReq_REST(AcceptedConnection *conn,
|
extern bool HTTPReq_REST(AcceptedConnection *conn,
|
||||||
const std::string& strURI,
|
const std::string& strURI,
|
||||||
|
|||||||
@@ -11,8 +11,14 @@
|
|||||||
|
|
||||||
#include "test/test_bitcoin.h"
|
#include "test/test_bitcoin.h"
|
||||||
|
|
||||||
|
#include "zcash/Address.hpp"
|
||||||
|
|
||||||
|
#include <fstream>
|
||||||
|
#include <unordered_set>
|
||||||
|
|
||||||
#include <boost/algorithm/string.hpp>
|
#include <boost/algorithm/string.hpp>
|
||||||
#include <boost/test/unit_test.hpp>
|
#include <boost/test/unit_test.hpp>
|
||||||
|
#include <boost/format.hpp>
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace json_spirit;
|
using namespace json_spirit;
|
||||||
@@ -218,4 +224,203 @@ BOOST_AUTO_TEST_CASE(rpc_wallet)
|
|||||||
BOOST_CHECK(CBitcoinAddress(arr[0].get_str()).Get() == demoAddress.Get());
|
BOOST_CHECK(CBitcoinAddress(arr[0].get_str()).Get() == demoAddress.Get());
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_SUITE_END()
|
/*
|
||||||
|
* This test covers RPC command z_exportwallet
|
||||||
|
*/
|
||||||
|
BOOST_AUTO_TEST_CASE(rpc_wallet_z_exportwallet)
|
||||||
|
{
|
||||||
|
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||||
|
|
||||||
|
// wallet should be empty
|
||||||
|
std::set<libzcash::PaymentAddress> addrs;
|
||||||
|
pwalletMain->GetPaymentAddresses(addrs);
|
||||||
|
BOOST_CHECK(addrs.size()==0);
|
||||||
|
|
||||||
|
// wallet should have one key
|
||||||
|
CZCPaymentAddress paymentAddress = pwalletMain->GenerateNewZKey();
|
||||||
|
pwalletMain->GetPaymentAddresses(addrs);
|
||||||
|
BOOST_CHECK(addrs.size()==1);
|
||||||
|
|
||||||
|
BOOST_CHECK_THROW(CallRPC("z_exportwallet"), runtime_error);
|
||||||
|
|
||||||
|
|
||||||
|
boost::filesystem::path temp = boost::filesystem::temp_directory_path() /
|
||||||
|
boost::filesystem::unique_path();
|
||||||
|
const std::string path = temp.native();
|
||||||
|
|
||||||
|
BOOST_CHECK_NO_THROW(CallRPC(string("z_exportwallet ") + path));
|
||||||
|
|
||||||
|
auto addr = paymentAddress.Get();
|
||||||
|
libzcash::SpendingKey key;
|
||||||
|
BOOST_CHECK(pwalletMain->GetSpendingKey(addr, key));
|
||||||
|
|
||||||
|
std::string s1 = paymentAddress.ToString();
|
||||||
|
std::string s2 = CZCSpendingKey(key).ToString();
|
||||||
|
|
||||||
|
// There's no way to really delete a private key so we will read in the
|
||||||
|
// exported wallet file and search for the spending key and payment address.
|
||||||
|
|
||||||
|
EnsureWalletIsUnlocked();
|
||||||
|
|
||||||
|
ifstream file;
|
||||||
|
file.open(path.c_str(), std::ios::in | std::ios::ate);
|
||||||
|
BOOST_CHECK(file.is_open());
|
||||||
|
bool fVerified = false;
|
||||||
|
int64_t nFilesize = std::max((int64_t)1, (int64_t)file.tellg());
|
||||||
|
file.seekg(0, file.beg);
|
||||||
|
while (file.good()) {
|
||||||
|
std::string line;
|
||||||
|
std::getline(file, line);
|
||||||
|
if (line.empty() || line[0] == '#')
|
||||||
|
continue;
|
||||||
|
if (line.find(s1) != std::string::npos && line.find(s2) != std::string::npos) {
|
||||||
|
fVerified = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
BOOST_CHECK(fVerified);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This test covers RPC command z_importwallet
|
||||||
|
*/
|
||||||
|
BOOST_AUTO_TEST_CASE(rpc_wallet_z_importwallet)
|
||||||
|
{
|
||||||
|
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||||
|
|
||||||
|
// error if no args
|
||||||
|
BOOST_CHECK_THROW(CallRPC("z_importwallet"), runtime_error);
|
||||||
|
|
||||||
|
// create a random key locally
|
||||||
|
auto testSpendingKey = libzcash::SpendingKey::random();
|
||||||
|
auto testPaymentAddress = testSpendingKey.address();
|
||||||
|
std::string testAddr = CZCPaymentAddress(testPaymentAddress).ToString();
|
||||||
|
std::string testKey = CZCSpendingKey(testSpendingKey).ToString();
|
||||||
|
|
||||||
|
// create test data using the random key
|
||||||
|
std::string format_str = "# Wallet dump created by Zcash v0.11.2.0.z8-9155cc6-dirty (2016-08-11 11:37:00 -0700)\n"
|
||||||
|
"# * Created on 2016-08-12T21:55:36Z\n"
|
||||||
|
"# * Best block at time of backup was 0 (0de0a3851fef2d433b9b4f51d4342bdd24c5ddd793eb8fba57189f07e9235d52),\n"
|
||||||
|
"# mined on 2009-01-03T18:15:05Z\n"
|
||||||
|
"\n"
|
||||||
|
"# Zkeys\n"
|
||||||
|
"\n"
|
||||||
|
"%s 2016-08-12T21:55:36Z # zaddr=%s\n"
|
||||||
|
"\n"
|
||||||
|
"\n# End of dump";
|
||||||
|
|
||||||
|
boost::format formatobject(format_str);
|
||||||
|
std::string testWalletDump = (formatobject % testKey % testAddr).str();
|
||||||
|
|
||||||
|
// write test data to file
|
||||||
|
boost::filesystem::path temp = boost::filesystem::temp_directory_path() /
|
||||||
|
boost::filesystem::unique_path();
|
||||||
|
const std::string path = temp.native();
|
||||||
|
std::ofstream file(path);
|
||||||
|
file << testWalletDump;
|
||||||
|
file << std::flush;
|
||||||
|
|
||||||
|
// wallet should currently be empty
|
||||||
|
std::set<libzcash::PaymentAddress> addrs;
|
||||||
|
pwalletMain->GetPaymentAddresses(addrs);
|
||||||
|
BOOST_CHECK(addrs.size()==0);
|
||||||
|
|
||||||
|
// import test data from file into wallet
|
||||||
|
BOOST_CHECK_NO_THROW(CallRPC(string("z_importwallet ") + path));
|
||||||
|
|
||||||
|
// wallet should now have one zkey
|
||||||
|
pwalletMain->GetPaymentAddresses(addrs);
|
||||||
|
BOOST_CHECK(addrs.size()==1);
|
||||||
|
|
||||||
|
// check that we have the spending key for the address
|
||||||
|
CZCPaymentAddress address(testAddr);
|
||||||
|
auto addr = address.Get();
|
||||||
|
BOOST_CHECK(pwalletMain->HaveSpendingKey(addr));
|
||||||
|
|
||||||
|
// Verify the spending key is the same as the test data
|
||||||
|
libzcash::SpendingKey k;
|
||||||
|
BOOST_CHECK(pwalletMain->GetSpendingKey(addr, k));
|
||||||
|
CZCSpendingKey spendingkey(k);
|
||||||
|
BOOST_CHECK_EQUAL(testKey, spendingkey.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This test covers RPC commands z_listaddresses, z_importkey, z_exportkey
|
||||||
|
*/
|
||||||
|
BOOST_AUTO_TEST_CASE(rpc_wallet_z_importexport)
|
||||||
|
{
|
||||||
|
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||||
|
Value retValue;
|
||||||
|
int n1 = 1000; // number of times to import/export
|
||||||
|
int n2 = 1000; // number of addresses to create and list
|
||||||
|
|
||||||
|
// error if no args
|
||||||
|
BOOST_CHECK_THROW(CallRPC("z_importkey"), runtime_error);
|
||||||
|
BOOST_CHECK_THROW(CallRPC("z_exportkey"), runtime_error);
|
||||||
|
|
||||||
|
// wallet should currently be empty
|
||||||
|
std::set<libzcash::PaymentAddress> addrs;
|
||||||
|
pwalletMain->GetPaymentAddresses(addrs);
|
||||||
|
BOOST_CHECK(addrs.size()==0);
|
||||||
|
|
||||||
|
// verify import and export key
|
||||||
|
for (int i = 0; i < n1; i++) {
|
||||||
|
// create a random key locally
|
||||||
|
auto testSpendingKey = libzcash::SpendingKey::random();
|
||||||
|
auto testPaymentAddress = testSpendingKey.address();
|
||||||
|
std::string testAddr = CZCPaymentAddress(testPaymentAddress).ToString();
|
||||||
|
std::string testKey = CZCSpendingKey(testSpendingKey).ToString();
|
||||||
|
BOOST_CHECK_NO_THROW(CallRPC(string("z_importkey ") + testKey));
|
||||||
|
BOOST_CHECK_NO_THROW(retValue = CallRPC(string("z_exportkey ") + testAddr));
|
||||||
|
BOOST_CHECK_EQUAL(retValue.get_str(), testKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify we can list the keys imported
|
||||||
|
BOOST_CHECK_NO_THROW(retValue = CallRPC("z_listaddresses"));
|
||||||
|
Array arr = retValue.get_array();
|
||||||
|
BOOST_CHECK(arr.size() == n1);
|
||||||
|
|
||||||
|
// Put addresses into a set
|
||||||
|
std::unordered_set<std::string> myaddrs;
|
||||||
|
for (Value element : arr) {
|
||||||
|
myaddrs.insert(element.get_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make new addresses for the set
|
||||||
|
for (int i=0; i<n2; i++) {
|
||||||
|
myaddrs.insert((pwalletMain->GenerateNewZKey()).ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify number of addresses stored in wallet is n1+n2
|
||||||
|
int numAddrs = myaddrs.size();
|
||||||
|
BOOST_CHECK(numAddrs == n1+n2);
|
||||||
|
pwalletMain->GetPaymentAddresses(addrs);
|
||||||
|
BOOST_CHECK(addrs.size()==numAddrs);
|
||||||
|
|
||||||
|
// Ask wallet to list addresses
|
||||||
|
BOOST_CHECK_NO_THROW(retValue = CallRPC("z_listaddresses"));
|
||||||
|
arr = retValue.get_array();
|
||||||
|
BOOST_CHECK(arr.size() == numAddrs);
|
||||||
|
|
||||||
|
// Create a set from them
|
||||||
|
std::unordered_set<std::string> listaddrs;
|
||||||
|
for (Value element : arr) {
|
||||||
|
listaddrs.insert(element.get_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify the two sets of addresses are the same
|
||||||
|
BOOST_CHECK(listaddrs.size() == numAddrs);
|
||||||
|
BOOST_CHECK(myaddrs == listaddrs);
|
||||||
|
|
||||||
|
// Add one more address
|
||||||
|
BOOST_CHECK_NO_THROW(retValue = CallRPC("z_getnewaddress"));
|
||||||
|
std::string newaddress = retValue.get_str();
|
||||||
|
CZCPaymentAddress pa(newaddress);
|
||||||
|
auto newAddr = pa.Get();
|
||||||
|
BOOST_CHECK(pwalletMain->HaveSpendingKey(newAddr));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_SUITE_END()
|
||||||
@@ -27,6 +27,10 @@ using namespace std;
|
|||||||
void EnsureWalletIsUnlocked();
|
void EnsureWalletIsUnlocked();
|
||||||
bool EnsureWalletIsAvailable(bool avoidException);
|
bool EnsureWalletIsAvailable(bool avoidException);
|
||||||
|
|
||||||
|
Value dumpwallet_impl(const Array& params, bool fHelp, bool fDumpZKeys);
|
||||||
|
Value importwallet_impl(const Array& params, bool fHelp, bool fImportZKeys);
|
||||||
|
|
||||||
|
|
||||||
std::string static EncodeDumpTime(int64_t nTime) {
|
std::string static EncodeDumpTime(int64_t nTime) {
|
||||||
return DateTimeStrFormat("%Y-%m-%dT%H:%M:%SZ", nTime);
|
return DateTimeStrFormat("%Y-%m-%dT%H:%M:%SZ", nTime);
|
||||||
}
|
}
|
||||||
@@ -217,6 +221,29 @@ Value importaddress(const Array& params, bool fHelp)
|
|||||||
return Value::null;
|
return Value::null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Value z_importwallet(const Array& params, bool fHelp)
|
||||||
|
{
|
||||||
|
if (!EnsureWalletIsAvailable(fHelp))
|
||||||
|
return Value::null;
|
||||||
|
|
||||||
|
if (fHelp || params.size() != 1)
|
||||||
|
throw runtime_error(
|
||||||
|
"z_importwallet \"filename\"\n"
|
||||||
|
"\nImports taddr and zaddr keys from a wallet export file (see z_exportwallet).\n"
|
||||||
|
"\nArguments:\n"
|
||||||
|
"1. \"filename\" (string, required) The wallet file\n"
|
||||||
|
"\nExamples:\n"
|
||||||
|
"\nDump the wallet\n"
|
||||||
|
+ HelpExampleCli("z_exportwallet", "\"test\"") +
|
||||||
|
"\nImport the wallet\n"
|
||||||
|
+ HelpExampleCli("z_importwallet", "\"test\"") +
|
||||||
|
"\nImport using the json rpc call\n"
|
||||||
|
+ HelpExampleRpc("z_importwallet", "\"test\"")
|
||||||
|
);
|
||||||
|
|
||||||
|
return importwallet_impl(params, fHelp, true);
|
||||||
|
}
|
||||||
|
|
||||||
Value importwallet(const Array& params, bool fHelp)
|
Value importwallet(const Array& params, bool fHelp)
|
||||||
{
|
{
|
||||||
if (!EnsureWalletIsAvailable(fHelp))
|
if (!EnsureWalletIsAvailable(fHelp))
|
||||||
@@ -225,7 +252,7 @@ Value importwallet(const Array& params, bool fHelp)
|
|||||||
if (fHelp || params.size() != 1)
|
if (fHelp || params.size() != 1)
|
||||||
throw runtime_error(
|
throw runtime_error(
|
||||||
"importwallet \"filename\"\n"
|
"importwallet \"filename\"\n"
|
||||||
"\nImports keys from a wallet dump file (see dumpwallet).\n"
|
"\nImports taddr keys from a wallet dump file (see dumpwallet).\n"
|
||||||
"\nArguments:\n"
|
"\nArguments:\n"
|
||||||
"1. \"filename\" (string, required) The wallet file\n"
|
"1. \"filename\" (string, required) The wallet file\n"
|
||||||
"\nExamples:\n"
|
"\nExamples:\n"
|
||||||
@@ -237,6 +264,11 @@ Value importwallet(const Array& params, bool fHelp)
|
|||||||
+ HelpExampleRpc("importwallet", "\"test\"")
|
+ HelpExampleRpc("importwallet", "\"test\"")
|
||||||
);
|
);
|
||||||
|
|
||||||
|
return importwallet_impl(params, fHelp, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
Value importwallet_impl(const Array& params, bool fHelp, bool fImportZKeys)
|
||||||
|
{
|
||||||
LOCK2(cs_main, pwalletMain->cs_wallet);
|
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||||
|
|
||||||
EnsureWalletIsUnlocked();
|
EnsureWalletIsUnlocked();
|
||||||
@@ -265,6 +297,34 @@ Value importwallet(const Array& params, bool fHelp)
|
|||||||
boost::split(vstr, line, boost::is_any_of(" "));
|
boost::split(vstr, line, boost::is_any_of(" "));
|
||||||
if (vstr.size() < 2)
|
if (vstr.size() < 2)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
// Let's see if the address is a valid Zcash spending key
|
||||||
|
if (fImportZKeys) {
|
||||||
|
try {
|
||||||
|
CZCSpendingKey spendingkey(vstr[0]);
|
||||||
|
libzcash::SpendingKey key = spendingkey.Get();
|
||||||
|
libzcash::PaymentAddress addr = key.address();
|
||||||
|
if (pwalletMain->HaveSpendingKey(addr)) {
|
||||||
|
LogPrintf("Skipping import of zaddr %s (key already present)\n", CZCPaymentAddress(addr).ToString());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
int64_t nTime = DecodeDumpTime(vstr[1]);
|
||||||
|
LogPrintf("Importing zaddr %s...\n", CZCPaymentAddress(addr).ToString());
|
||||||
|
if (!pwalletMain->AddZKey(key)) {
|
||||||
|
// Something went wrong
|
||||||
|
fGood = false;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// Successfully imported zaddr. Now import the metadata.
|
||||||
|
pwalletMain->mapZKeyMetadata[addr].nCreateTime = nTime;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
catch (const std::runtime_error &e) {
|
||||||
|
LogPrintf("Importing detected an error: %s\n", e.what());
|
||||||
|
// Not a valid spending key, so carry on and see if it's a Bitcoin style address.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
CBitcoinSecret vchSecret;
|
CBitcoinSecret vchSecret;
|
||||||
if (!vchSecret.SetString(vstr[0]))
|
if (!vchSecret.SetString(vstr[0]))
|
||||||
continue;
|
continue;
|
||||||
@@ -359,15 +419,35 @@ Value dumpprivkey(const Array& params, bool fHelp)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Value dumpwallet(const Array& params, bool fHelp)
|
|
||||||
|
Value z_exportwallet(const Array& params, bool fHelp)
|
||||||
{
|
{
|
||||||
if (!EnsureWalletIsAvailable(fHelp))
|
if (!EnsureWalletIsAvailable(fHelp))
|
||||||
return Value::null;
|
return Value::null;
|
||||||
|
|
||||||
|
if (fHelp || params.size() != 1)
|
||||||
|
throw runtime_error(
|
||||||
|
"z_exportwallet \"filename\"\n"
|
||||||
|
"\nExports all wallet keys, for taddr and zaddr, in a human-readable format.\n"
|
||||||
|
"\nArguments:\n"
|
||||||
|
"1. \"filename\" (string, required) The filename\n"
|
||||||
|
"\nExamples:\n"
|
||||||
|
+ HelpExampleCli("z_exportwallet", "\"test\"")
|
||||||
|
+ HelpExampleRpc("z_exportwallet", "\"test\"")
|
||||||
|
);
|
||||||
|
|
||||||
|
return dumpwallet_impl(params, fHelp, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
Value dumpwallet(const Array& params, bool fHelp)
|
||||||
|
{
|
||||||
|
if (!EnsureWalletIsAvailable(fHelp))
|
||||||
|
return Value::null;
|
||||||
|
|
||||||
if (fHelp || params.size() != 1)
|
if (fHelp || params.size() != 1)
|
||||||
throw runtime_error(
|
throw runtime_error(
|
||||||
"dumpwallet \"filename\"\n"
|
"dumpwallet \"filename\"\n"
|
||||||
"\nDumps all wallet keys in a human-readable format.\n"
|
"\nDumps taddr wallet keys in a human-readable format.\n"
|
||||||
"\nArguments:\n"
|
"\nArguments:\n"
|
||||||
"1. \"filename\" (string, required) The filename\n"
|
"1. \"filename\" (string, required) The filename\n"
|
||||||
"\nExamples:\n"
|
"\nExamples:\n"
|
||||||
@@ -375,6 +455,11 @@ Value dumpwallet(const Array& params, bool fHelp)
|
|||||||
+ HelpExampleRpc("dumpwallet", "\"test\"")
|
+ HelpExampleRpc("dumpwallet", "\"test\"")
|
||||||
);
|
);
|
||||||
|
|
||||||
|
return dumpwallet_impl(params, fHelp, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
Value dumpwallet_impl(const Array& params, bool fHelp, bool fDumpZKeys)
|
||||||
|
{
|
||||||
LOCK2(cs_main, pwalletMain->cs_wallet);
|
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||||
|
|
||||||
EnsureWalletIsUnlocked();
|
EnsureWalletIsUnlocked();
|
||||||
@@ -398,7 +483,7 @@ Value dumpwallet(const Array& params, bool fHelp)
|
|||||||
std::sort(vKeyBirth.begin(), vKeyBirth.end());
|
std::sort(vKeyBirth.begin(), vKeyBirth.end());
|
||||||
|
|
||||||
// produce output
|
// produce output
|
||||||
file << strprintf("# Wallet dump created by Bitcoin %s (%s)\n", CLIENT_BUILD, CLIENT_DATE);
|
file << strprintf("# Wallet dump created by Zcash %s (%s)\n", CLIENT_BUILD, CLIENT_DATE);
|
||||||
file << strprintf("# * Created on %s\n", EncodeDumpTime(GetTime()));
|
file << strprintf("# * Created on %s\n", EncodeDumpTime(GetTime()));
|
||||||
file << strprintf("# * Best block at time of backup was %i (%s),\n", chainActive.Height(), chainActive.Tip()->GetBlockHash().ToString());
|
file << strprintf("# * Best block at time of backup was %i (%s),\n", chainActive.Height(), chainActive.Tip()->GetBlockHash().ToString());
|
||||||
file << strprintf("# mined on %s\n", EncodeDumpTime(chainActive.Tip()->GetBlockTime()));
|
file << strprintf("# mined on %s\n", EncodeDumpTime(chainActive.Tip()->GetBlockTime()));
|
||||||
@@ -419,7 +504,123 @@ Value dumpwallet(const Array& params, bool fHelp)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
file << "\n";
|
file << "\n";
|
||||||
|
|
||||||
|
if (fDumpZKeys) {
|
||||||
|
std::set<libzcash::PaymentAddress> addresses;
|
||||||
|
pwalletMain->GetPaymentAddresses(addresses);
|
||||||
|
file << "\n";
|
||||||
|
file << "# Zkeys\n";
|
||||||
|
file << "\n";
|
||||||
|
for (auto addr : addresses ) {
|
||||||
|
libzcash::SpendingKey key;
|
||||||
|
if (pwalletMain->GetSpendingKey(addr, key)) {
|
||||||
|
std::string strTime = EncodeDumpTime(pwalletMain->mapZKeyMetadata[addr].nCreateTime);
|
||||||
|
file << strprintf("%s %s # zaddr=%s\n", CZCSpendingKey(key).ToString(), strTime, CZCPaymentAddress(addr).ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
file << "# End of dump\n";
|
file << "# End of dump\n";
|
||||||
file.close();
|
file.close();
|
||||||
return Value::null;
|
return Value::null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Value z_importkey(const Array& params, bool fHelp)
|
||||||
|
{
|
||||||
|
if (!EnsureWalletIsAvailable(fHelp))
|
||||||
|
return Value::null;
|
||||||
|
|
||||||
|
if (fHelp || params.size() < 1 || params.size() > 3)
|
||||||
|
throw runtime_error(
|
||||||
|
"z_importkey \"zkey\" ( \"label\" rescan )\n"
|
||||||
|
"\nAdds a zkey (as returned by z_exportkey) to your wallet.\n"
|
||||||
|
"\nArguments:\n"
|
||||||
|
"1. \"zkey\" (string, required) The zkey (see z_exportkey)\n"
|
||||||
|
"2. rescan (boolean, optional, default=true) Rescan the wallet for transactions\n"
|
||||||
|
"\nNote: This call can take minutes to complete if rescan is true.\n"
|
||||||
|
"\nExamples:\n"
|
||||||
|
"\nExport a zkey\n"
|
||||||
|
+ HelpExampleCli("z_exportkey", "\"myaddress\"") +
|
||||||
|
"\nImport the zkey with rescan\n"
|
||||||
|
+ HelpExampleCli("z_importkey", "\"mykey\"") +
|
||||||
|
"\nImport using a label and without rescan\n"
|
||||||
|
+ HelpExampleCli("z_importkey", "\"mykey\" \"testing\" false") +
|
||||||
|
"\nAs a JSON-RPC call\n"
|
||||||
|
+ HelpExampleRpc("z_importkey", "\"mykey\", \"testing\", false")
|
||||||
|
);
|
||||||
|
|
||||||
|
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||||
|
|
||||||
|
EnsureWalletIsUnlocked();
|
||||||
|
|
||||||
|
// Whether to perform rescan after import
|
||||||
|
bool fRescan = true;
|
||||||
|
if (params.size() > 1)
|
||||||
|
fRescan = params[1].get_bool();
|
||||||
|
|
||||||
|
string strSecret = params[0].get_str();
|
||||||
|
CZCSpendingKey spendingkey(strSecret);
|
||||||
|
auto key = spendingkey.Get();
|
||||||
|
auto addr = key.address();
|
||||||
|
|
||||||
|
{
|
||||||
|
// Don't throw error in case a key is already there
|
||||||
|
if (pwalletMain->HaveSpendingKey(addr))
|
||||||
|
return Value::null;
|
||||||
|
|
||||||
|
pwalletMain->MarkDirty();
|
||||||
|
|
||||||
|
if (!pwalletMain-> AddZKey(key))
|
||||||
|
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding spending key to wallet");
|
||||||
|
|
||||||
|
pwalletMain->mapZKeyMetadata[addr].nCreateTime = 1;
|
||||||
|
|
||||||
|
// We want to scan for transactions and notes
|
||||||
|
if (fRescan) {
|
||||||
|
pwalletMain->ScanForWalletTransactions(chainActive.Genesis(), true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Value::null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Value z_exportkey(const Array& params, bool fHelp)
|
||||||
|
{
|
||||||
|
if (!EnsureWalletIsAvailable(fHelp))
|
||||||
|
return Value::null;
|
||||||
|
|
||||||
|
if (fHelp || params.size() != 1)
|
||||||
|
throw runtime_error(
|
||||||
|
"z_exportkey \"zaddr\"\n"
|
||||||
|
"\nReveals the zkey corresponding to 'zaddr'.\n"
|
||||||
|
"Then the z_importkey can be used with this output\n"
|
||||||
|
"\nArguments:\n"
|
||||||
|
"1. \"zaddr\" (string, required) The zaddr for the private key\n"
|
||||||
|
"\nResult:\n"
|
||||||
|
"\"key\" (string) The private key\n"
|
||||||
|
"\nExamples:\n"
|
||||||
|
+ HelpExampleCli("z_exportkey", "\"myaddress\"")
|
||||||
|
+ HelpExampleCli("z_importkey", "\"mykey\"")
|
||||||
|
+ HelpExampleRpc("z_exportkey", "\"myaddress\"")
|
||||||
|
);
|
||||||
|
|
||||||
|
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||||
|
|
||||||
|
EnsureWalletIsUnlocked();
|
||||||
|
|
||||||
|
string strAddress = params[0].get_str();
|
||||||
|
|
||||||
|
CZCPaymentAddress address(strAddress);
|
||||||
|
auto addr = address.Get();
|
||||||
|
|
||||||
|
libzcash::SpendingKey k;
|
||||||
|
if (!pwalletMain->GetSpendingKey(addr, k))
|
||||||
|
throw JSONRPCError(RPC_WALLET_ERROR, "Wallet does not hold private zkey for this zaddr");
|
||||||
|
|
||||||
|
CZCSpendingKey spendingkey(k);
|
||||||
|
return spendingkey.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2769,3 +2769,61 @@ Value zc_raw_keygen(const json_spirit::Array& params, bool fHelp)
|
|||||||
result.push_back(Pair("zcviewingkey", viewing_hex));
|
result.push_back(Pair("zcviewingkey", viewing_hex));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Value z_getnewaddress(const Array& params, bool fHelp)
|
||||||
|
{
|
||||||
|
if (!EnsureWalletIsAvailable(fHelp))
|
||||||
|
return Value::null;
|
||||||
|
|
||||||
|
if (fHelp || params.size() > 1)
|
||||||
|
throw runtime_error(
|
||||||
|
"z_getnewaddress\n"
|
||||||
|
"\nReturns a new zaddr for receiving payments.\n"
|
||||||
|
"\nArguments:\n"
|
||||||
|
"\nResult:\n"
|
||||||
|
"\"zcashaddress\" (string) The new zaddr\n"
|
||||||
|
"\nExamples:\n"
|
||||||
|
+ HelpExampleCli("z_getnewaddress", "")
|
||||||
|
+ HelpExampleRpc("z_getnewaddress", "")
|
||||||
|
);
|
||||||
|
|
||||||
|
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||||
|
|
||||||
|
CZCPaymentAddress pubaddr = pwalletMain->GenerateNewZKey();
|
||||||
|
std::string result = pubaddr.ToString();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Value z_listaddresses(const Array& params, bool fHelp)
|
||||||
|
{
|
||||||
|
if (!EnsureWalletIsAvailable(fHelp))
|
||||||
|
return Value::null;
|
||||||
|
|
||||||
|
if (fHelp || params.size() > 1)
|
||||||
|
throw runtime_error(
|
||||||
|
"z_listaddresses\n"
|
||||||
|
"\nReturns the list of zaddr belonging to the wallet.\n"
|
||||||
|
"\nArguments:\n"
|
||||||
|
"\nResult:\n"
|
||||||
|
"[ (json array of string)\n"
|
||||||
|
" \"zaddr\" (string) a zaddr belonging to the wallet\n"
|
||||||
|
" ,...\n"
|
||||||
|
"]\n"
|
||||||
|
"\nExamples:\n"
|
||||||
|
+ HelpExampleCli("z_listaddresses", "")
|
||||||
|
+ HelpExampleRpc("z_listaddresses", "")
|
||||||
|
);
|
||||||
|
|
||||||
|
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||||
|
|
||||||
|
Array ret;
|
||||||
|
std::set<libzcash::PaymentAddress> addresses;
|
||||||
|
pwalletMain->GetPaymentAddresses(addresses);
|
||||||
|
for (auto addr : addresses ) {
|
||||||
|
ret.push_back(CZCPaymentAddress(addr).ToString());
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -25,6 +25,7 @@
|
|||||||
#include <boost/thread.hpp>
|
#include <boost/thread.hpp>
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
using namespace libzcash;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Settings
|
* Settings
|
||||||
@@ -70,6 +71,47 @@ const CWalletTx* CWallet::GetWalletTx(const uint256& hash) const
|
|||||||
return &(it->second);
|
return &(it->second);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Generate a new spending key and return its public payment address
|
||||||
|
CZCPaymentAddress CWallet::GenerateNewZKey()
|
||||||
|
{
|
||||||
|
AssertLockHeld(cs_wallet); // mapZKeyMetadata
|
||||||
|
auto k = SpendingKey::random();
|
||||||
|
auto addr = k.address();
|
||||||
|
|
||||||
|
// Check for collision, even though it is unlikely to ever occur
|
||||||
|
if (CCryptoKeyStore::HaveSpendingKey(addr))
|
||||||
|
throw std::runtime_error("CWallet::GenerateNewZKey(): Collision detected");
|
||||||
|
|
||||||
|
// Create new metadata
|
||||||
|
int64_t nCreationTime = GetTime();
|
||||||
|
mapZKeyMetadata[addr] = CKeyMetadata(nCreationTime);
|
||||||
|
|
||||||
|
CZCPaymentAddress pubaddr(addr);
|
||||||
|
if (!AddZKey(k))
|
||||||
|
throw std::runtime_error("CWallet::GenerateNewZKey(): AddZKey failed");
|
||||||
|
return pubaddr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add spending key to keystore and persist to disk
|
||||||
|
bool CWallet::AddZKey(const libzcash::SpendingKey &key)
|
||||||
|
{
|
||||||
|
AssertLockHeld(cs_wallet); // mapZKeyMetadata
|
||||||
|
auto addr = key.address();
|
||||||
|
|
||||||
|
if (!CCryptoKeyStore::AddSpendingKey(key))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!fFileBacked)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (!IsCrypted()) {
|
||||||
|
return CWalletDB(strWalletFile).WriteZKey(addr,
|
||||||
|
key,
|
||||||
|
mapZKeyMetadata[addr]);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
CPubKey CWallet::GenerateNewKey()
|
CPubKey CWallet::GenerateNewKey()
|
||||||
{
|
{
|
||||||
AssertLockHeld(cs_wallet); // mapKeyMetadata
|
AssertLockHeld(cs_wallet); // mapKeyMetadata
|
||||||
@@ -149,11 +191,23 @@ bool CWallet::LoadKeyMetadata(const CPubKey &pubkey, const CKeyMetadata &meta)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CWallet::LoadZKeyMetadata(const PaymentAddress &addr, const CKeyMetadata &meta)
|
||||||
|
{
|
||||||
|
AssertLockHeld(cs_wallet); // mapZKeyMetadata
|
||||||
|
mapZKeyMetadata[addr] = meta;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool CWallet::LoadCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret)
|
bool CWallet::LoadCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret)
|
||||||
{
|
{
|
||||||
return CCryptoKeyStore::AddCryptedKey(vchPubKey, vchCryptedSecret);
|
return CCryptoKeyStore::AddCryptedKey(vchPubKey, vchCryptedSecret);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CWallet::LoadZKey(const libzcash::SpendingKey &key)
|
||||||
|
{
|
||||||
|
return CCryptoKeyStore::AddSpendingKey(key);
|
||||||
|
}
|
||||||
|
|
||||||
bool CWallet::AddCScript(const CScript& redeemScript)
|
bool CWallet::AddCScript(const CScript& redeemScript)
|
||||||
{
|
{
|
||||||
if (!CCryptoKeyStore::AddCScript(redeemScript))
|
if (!CCryptoKeyStore::AddCScript(redeemScript))
|
||||||
|
|||||||
@@ -18,6 +18,8 @@
|
|||||||
#include "wallet/crypter.h"
|
#include "wallet/crypter.h"
|
||||||
#include "wallet/wallet_ismine.h"
|
#include "wallet/wallet_ismine.h"
|
||||||
#include "wallet/walletdb.h"
|
#include "wallet/walletdb.h"
|
||||||
|
#include "zcash/Address.hpp"
|
||||||
|
#include "base58.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <map>
|
#include <map>
|
||||||
@@ -486,6 +488,7 @@ public:
|
|||||||
|
|
||||||
std::set<int64_t> setKeyPool;
|
std::set<int64_t> setKeyPool;
|
||||||
std::map<CKeyID, CKeyMetadata> mapKeyMetadata;
|
std::map<CKeyID, CKeyMetadata> mapKeyMetadata;
|
||||||
|
std::map<libzcash::PaymentAddress, CKeyMetadata> mapZKeyMetadata;
|
||||||
|
|
||||||
typedef std::map<unsigned int, CMasterKey> MasterKeyMap;
|
typedef std::map<unsigned int, CMasterKey> MasterKeyMap;
|
||||||
MasterKeyMap mapMasterKeys;
|
MasterKeyMap mapMasterKeys;
|
||||||
@@ -595,6 +598,19 @@ public:
|
|||||||
|
|
||||||
void GetKeyBirthTimes(std::map<CKeyID, int64_t> &mapKeyBirth) const;
|
void GetKeyBirthTimes(std::map<CKeyID, int64_t> &mapKeyBirth) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ZKeys
|
||||||
|
*/
|
||||||
|
//! Generates a new zaddr
|
||||||
|
CZCPaymentAddress GenerateNewZKey();
|
||||||
|
//! Adds spending key to the store, and saves it to disk
|
||||||
|
bool AddZKey(const libzcash::SpendingKey &key);
|
||||||
|
//! Adds spending key to the store, without saving it to disk (used by LoadWallet)
|
||||||
|
bool LoadZKey(const libzcash::SpendingKey &key);
|
||||||
|
//! Load spending key metadata (used by LoadWallet)
|
||||||
|
bool LoadZKeyMetadata(const libzcash::PaymentAddress &addr, const CKeyMetadata &meta);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Increment the next transaction order id
|
* Increment the next transaction order id
|
||||||
* @return next transaction order id
|
* @return next transaction order id
|
||||||
|
|||||||
@@ -110,6 +110,17 @@ bool CWalletDB::WriteMasterKey(unsigned int nID, const CMasterKey& kMasterKey)
|
|||||||
return Write(std::make_pair(std::string("mkey"), nID), kMasterKey, true);
|
return Write(std::make_pair(std::string("mkey"), nID), kMasterKey, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CWalletDB::WriteZKey(const libzcash::PaymentAddress& addr, const libzcash::SpendingKey& key, const CKeyMetadata &keyMeta)
|
||||||
|
{
|
||||||
|
nWalletDBUpdated++;
|
||||||
|
|
||||||
|
if (!Write(std::make_pair(std::string("zkeymeta"), addr), keyMeta))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// pair is: tuple_key("zkey", paymentaddress) --> secretkey
|
||||||
|
return Write(std::make_pair(std::string("zkey"), addr), key, false);
|
||||||
|
}
|
||||||
|
|
||||||
bool CWalletDB::WriteCScript(const uint160& hash, const CScript& redeemScript)
|
bool CWalletDB::WriteCScript(const uint160& hash, const CScript& redeemScript)
|
||||||
{
|
{
|
||||||
nWalletDBUpdated++;
|
nWalletDBUpdated++;
|
||||||
@@ -330,13 +341,15 @@ public:
|
|||||||
unsigned int nKeys;
|
unsigned int nKeys;
|
||||||
unsigned int nCKeys;
|
unsigned int nCKeys;
|
||||||
unsigned int nKeyMeta;
|
unsigned int nKeyMeta;
|
||||||
|
unsigned int nZKeys;
|
||||||
|
unsigned int nZKeyMeta;
|
||||||
bool fIsEncrypted;
|
bool fIsEncrypted;
|
||||||
bool fAnyUnordered;
|
bool fAnyUnordered;
|
||||||
int nFileVersion;
|
int nFileVersion;
|
||||||
vector<uint256> vWalletUpgrade;
|
vector<uint256> vWalletUpgrade;
|
||||||
|
|
||||||
CWalletScanState() {
|
CWalletScanState() {
|
||||||
nKeys = nCKeys = nKeyMeta = 0;
|
nKeys = nCKeys = nKeyMeta = nZKeys = nZKeyMeta = 0;
|
||||||
fIsEncrypted = false;
|
fIsEncrypted = false;
|
||||||
fAnyUnordered = false;
|
fAnyUnordered = false;
|
||||||
nFileVersion = 0;
|
nFileVersion = 0;
|
||||||
@@ -429,6 +442,21 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
|
|||||||
// so set the wallet birthday to the beginning of time.
|
// so set the wallet birthday to the beginning of time.
|
||||||
pwallet->nTimeFirstKey = 1;
|
pwallet->nTimeFirstKey = 1;
|
||||||
}
|
}
|
||||||
|
else if (strType == "zkey")
|
||||||
|
{
|
||||||
|
libzcash::PaymentAddress addr;
|
||||||
|
ssKey >> addr;
|
||||||
|
libzcash::SpendingKey key;
|
||||||
|
ssValue >> key;
|
||||||
|
|
||||||
|
if (!pwallet->LoadZKey(key))
|
||||||
|
{
|
||||||
|
strErr = "Error reading wallet database: LoadZKey failed";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
wss.nZKeys++;
|
||||||
|
}
|
||||||
else if (strType == "key" || strType == "wkey")
|
else if (strType == "key" || strType == "wkey")
|
||||||
{
|
{
|
||||||
CPubKey vchPubKey;
|
CPubKey vchPubKey;
|
||||||
@@ -538,6 +566,18 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
|
|||||||
(keyMeta.nCreateTime < pwallet->nTimeFirstKey))
|
(keyMeta.nCreateTime < pwallet->nTimeFirstKey))
|
||||||
pwallet->nTimeFirstKey = keyMeta.nCreateTime;
|
pwallet->nTimeFirstKey = keyMeta.nCreateTime;
|
||||||
}
|
}
|
||||||
|
else if (strType == "zkeymeta")
|
||||||
|
{
|
||||||
|
libzcash::PaymentAddress addr;
|
||||||
|
ssKey >> addr;
|
||||||
|
CKeyMetadata keyMeta;
|
||||||
|
ssValue >> keyMeta;
|
||||||
|
wss.nZKeyMeta++;
|
||||||
|
|
||||||
|
pwallet->LoadZKeyMetadata(addr, keyMeta);
|
||||||
|
|
||||||
|
// ignore earliest key creation time as taddr will exist before any zaddr
|
||||||
|
}
|
||||||
else if (strType == "defaultkey")
|
else if (strType == "defaultkey")
|
||||||
{
|
{
|
||||||
ssValue >> pwallet->vchDefaultKey;
|
ssValue >> pwallet->vchDefaultKey;
|
||||||
@@ -601,6 +641,7 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
|
|||||||
static bool IsKeyType(string strType)
|
static bool IsKeyType(string strType)
|
||||||
{
|
{
|
||||||
return (strType== "key" || strType == "wkey" ||
|
return (strType== "key" || strType == "wkey" ||
|
||||||
|
strType == "zkey" ||
|
||||||
strType == "mkey" || strType == "ckey");
|
strType == "mkey" || strType == "ckey");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -685,6 +726,10 @@ DBErrors CWalletDB::LoadWallet(CWallet* pwallet)
|
|||||||
LogPrintf("Keys: %u plaintext, %u encrypted, %u w/ metadata, %u total\n",
|
LogPrintf("Keys: %u plaintext, %u encrypted, %u w/ metadata, %u total\n",
|
||||||
wss.nKeys, wss.nCKeys, wss.nKeyMeta, wss.nKeys + wss.nCKeys);
|
wss.nKeys, wss.nCKeys, wss.nKeyMeta, wss.nKeys + wss.nCKeys);
|
||||||
|
|
||||||
|
// TODO: Keep track of encrypted ZKeys
|
||||||
|
LogPrintf("ZKeys: %u plaintext, -- encrypted, %u w/metadata, %u total\n",
|
||||||
|
wss.nZKeys, wss.nZKeyMeta, wss.nZKeys + 0);
|
||||||
|
|
||||||
// nTimeFirstKey is only reliable if all keys have metadata
|
// nTimeFirstKey is only reliable if all keys have metadata
|
||||||
if ((wss.nKeys + wss.nCKeys) != wss.nKeyMeta)
|
if ((wss.nKeys + wss.nCKeys) != wss.nKeyMeta)
|
||||||
pwallet->nTimeFirstKey = 1; // 0 would be considered 'no value'
|
pwallet->nTimeFirstKey = 1; // 0 would be considered 'no value'
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
#include "wallet/db.h"
|
#include "wallet/db.h"
|
||||||
#include "key.h"
|
#include "key.h"
|
||||||
#include "keystore.h"
|
#include "keystore.h"
|
||||||
|
#include "zcash/Address.hpp"
|
||||||
|
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
@@ -130,6 +131,9 @@ public:
|
|||||||
static bool Recover(CDBEnv& dbenv, const std::string& filename, bool fOnlyKeys);
|
static bool Recover(CDBEnv& dbenv, const std::string& filename, bool fOnlyKeys);
|
||||||
static bool Recover(CDBEnv& dbenv, const std::string& filename);
|
static bool Recover(CDBEnv& dbenv, const std::string& filename);
|
||||||
|
|
||||||
|
/// Write spending key to wallet database, where key is payment address and value is spending key.
|
||||||
|
bool WriteZKey(const libzcash::PaymentAddress& addr, const libzcash::SpendingKey& key, const CKeyMetadata &keyMeta);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
CWalletDB(const CWalletDB&);
|
CWalletDB(const CWalletDB&);
|
||||||
void operator=(const CWalletDB&);
|
void operator=(const CWalletDB&);
|
||||||
|
|||||||
Reference in New Issue
Block a user