From 5e360fb29f1f3b8447d693c3b3bf720cc5e03006 Mon Sep 17 00:00:00 2001 From: Eirik Ogilvie-Wigley Date: Wed, 12 Sep 2018 05:01:08 -0600 Subject: [PATCH] Add sapling spending keys to z_exportwallet --- qa/pull-tester/rpc-tests.sh | 1 + qa/rpc-tests/wallet_import_export.py | 54 ++++++++++++++++++++++++++++ src/keystore.cpp | 10 ++++++ src/keystore.h | 5 +++ src/wallet/rpcdump.cpp | 21 ++++++++--- src/wallet/wallet.cpp | 11 ++---- 6 files changed, 90 insertions(+), 12 deletions(-) create mode 100755 qa/rpc-tests/wallet_import_export.py diff --git a/qa/pull-tester/rpc-tests.sh b/qa/pull-tester/rpc-tests.sh index 25ecc409a..fd71877f2 100755 --- a/qa/pull-tester/rpc-tests.sh +++ b/qa/pull-tester/rpc-tests.sh @@ -16,6 +16,7 @@ testScripts=( 'wallet_treestate.py' 'wallet_anchorfork.py' 'wallet_changeindicator.py' + 'wallet_import_export.py' 'wallet_protectcoinbase.py' 'wallet_shieldcoinbase.py' 'wallet_mergetoaddress.py' diff --git a/qa/rpc-tests/wallet_import_export.py b/qa/rpc-tests/wallet_import_export.py new file mode 100755 index 000000000..b23143c9e --- /dev/null +++ b/qa/rpc-tests/wallet_import_export.py @@ -0,0 +1,54 @@ +#!/usr/bin/env python2 +# Copyright (c) 2018 The Zcash developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import assert_true, start_nodes + +class WalletImportExportTest (BitcoinTestFramework): + def setup_network(self, split=False): + extra_args = [["-exportdir={}/export{}".format(self.options.tmpdir, i)] for i in range(2)] + self.nodes = start_nodes(2, self.options.tmpdir, extra_args) + + def run_test(self): + sprout_address0 = self.nodes[0].z_getnewaddress('sprout') + sapling_address0 = self.nodes[0].z_getnewaddress('sapling') + + # node 0 should have the keys + dump_path = self.nodes[0].z_exportwallet('walletdump') + (t_keys0, sprout_keys0, sapling_keys0) = parse_wallet_file(dump_path) + + assert_true(sprout_address0 in sprout_keys0) + assert_true(sapling_address0 in sapling_keys0) + + # node 1 should not + dump_path = self.nodes[1].z_exportwallet('walletdump') + (t_keys1, sprout_keys1, sapling_keys1) = parse_wallet_file(dump_path) + + assert_true(sprout_address0 not in sprout_keys1) + assert_true(sapling_address0 not in sapling_keys1) + +# Helper functions +def parse_wallet_file(dump_path): + file_lines = open(dump_path, "r").readlines() + + (t_keys, i) = parse_wallet_file_lines(file_lines, 0) + (sprout_keys, i) = parse_wallet_file_lines(file_lines, i) + (sapling_keys, i) = parse_wallet_file_lines(file_lines, i) + + return (t_keys, sprout_keys, sapling_keys) + +def parse_wallet_file_lines(file_lines, i): + keys = [] + # skip blank lines and comments + while i < len(file_lines) and (file_lines[i] == '\n' or file_lines[i].startswith("#")): + i += 1 + # add keys until we hit another blank line or comment + while i < len(file_lines) and not (file_lines[i] == '\n' or file_lines[i].startswith("#")): + keys.append(file_lines[i]) + i += 1 + return ("".join(keys), i) + +if __name__ == '__main__': + WalletImportExportTest().main() \ No newline at end of file diff --git a/src/keystore.cpp b/src/keystore.cpp index 8262c8aab..fd42f7634 100644 --- a/src/keystore.cpp +++ b/src/keystore.cpp @@ -226,3 +226,13 @@ bool CBasicKeyStore::GetSaplingIncomingViewingKey(const libzcash::SaplingPayment } return false; } + +bool CBasicKeyStore::GetSaplingExtendedSpendingKey(const libzcash::SaplingPaymentAddress &addr, + libzcash::SaplingExtendedSpendingKey &extskOut) const { + libzcash::SaplingIncomingViewingKey ivk; + libzcash::SaplingFullViewingKey fvk; + + return GetSaplingIncomingViewingKey(addr, ivk) && + GetSaplingFullViewingKey(ivk, fvk) && + GetSaplingSpendingKey(fvk, extskOut); +} diff --git a/src/keystore.h b/src/keystore.h index a8a8f62f5..5a80384bb 100644 --- a/src/keystore.h +++ b/src/keystore.h @@ -273,6 +273,11 @@ public: virtual bool GetSaplingIncomingViewingKey( const libzcash::SaplingPaymentAddress &addr, libzcash::SaplingIncomingViewingKey& ivkOut) const; + + bool GetSaplingExtendedSpendingKey( + const libzcash::SaplingPaymentAddress &addr, + libzcash::SaplingExtendedSpendingKey &extskOut) const; + void GetSaplingPaymentAddresses(std::set &setAddress) const { setAddress.clear(); diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp index f6bc6528f..87d29a6ec 100644 --- a/src/wallet/rpcdump.cpp +++ b/src/wallet/rpcdump.cpp @@ -318,7 +318,7 @@ UniValue importwallet_impl(const UniValue& params, bool fHelp, bool fImportZKeys continue; } else { LogPrint("zrpc", "Importing detected an error: invalid spending key. Trying as a transparent key...\n"); - // Not a valid spending key, so carry on and see if it's a Zcash style address. + // Not a valid spending key, so carry on and see if it's a Zcash style t-address. } } @@ -529,18 +529,31 @@ UniValue dumpwallet_impl(const UniValue& params, bool fHelp, bool fDumpZKeys) file << "\n"; if (fDumpZKeys) { - std::set addresses; - pwalletMain->GetSproutPaymentAddresses(addresses); + std::set sproutAddresses; + pwalletMain->GetSproutPaymentAddresses(sproutAddresses); file << "\n"; file << "# Zkeys\n"; file << "\n"; - for (auto addr : addresses ) { + for (auto addr : sproutAddresses) { libzcash::SproutSpendingKey key; if (pwalletMain->GetSproutSpendingKey(addr, key)) { std::string strTime = EncodeDumpTime(pwalletMain->mapSproutZKeyMetadata[addr].nCreateTime); file << strprintf("%s %s # zaddr=%s\n", EncodeSpendingKey(key), strTime, EncodePaymentAddress(addr)); } } + std::set saplingAddresses; + pwalletMain->GetSaplingPaymentAddresses(saplingAddresses); + file << "\n"; + file << "# Sapling keys\n"; + file << "\n"; + for (auto addr : saplingAddresses) { + libzcash::SaplingExtendedSpendingKey extsk; + if (pwalletMain->GetSaplingExtendedSpendingKey(addr, extsk)) { + auto ivk = extsk.expsk.full_viewing_key().in_viewing_key(); + std::string strTime = EncodeDumpTime(pwalletMain->mapSaplingZKeyMetadata[ivk].nCreateTime); + file << strprintf("%s %s # zaddr=%s\n", EncodeSpendingKey(extsk), strTime, EncodePaymentAddress(addr)); + } + } file << "\n"; } diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index f4e692219..abd064501 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -4553,14 +4553,9 @@ boost::optional GetSpendingKeyForPaymentAddress::operator boost::optional GetSpendingKeyForPaymentAddress::operator()( const libzcash::SaplingPaymentAddress &zaddr) const { - libzcash::SaplingIncomingViewingKey ivk; - libzcash::SaplingFullViewingKey fvk; - libzcash::SaplingExtendedSpendingKey sk; - - if (m_wallet->GetSaplingIncomingViewingKey(zaddr, ivk) && - m_wallet->GetSaplingFullViewingKey(ivk, fvk) && - m_wallet->GetSaplingSpendingKey(fvk, sk)) { - return libzcash::SpendingKey(sk); + libzcash::SaplingExtendedSpendingKey extsk; + if (m_wallet->GetSaplingExtendedSpendingKey(zaddr, extsk)) { + return libzcash::SpendingKey(extsk); } else { return boost::none; }