From 2fe39561ec8845cbf812c9b95e45648190df0e46 Mon Sep 17 00:00:00 2001 From: Eirik Ogilvie-Wigley Date: Fri, 14 Sep 2018 17:27:20 -0600 Subject: [PATCH] Export zip32 metadata with sapling keys --- qa/rpc-tests/wallet_import_export.py | 11 +++++++++-- src/wallet/rpcdump.cpp | 12 +++++++----- src/wallet/wallet.cpp | 11 +++++++++-- src/wallet/wallet.h | 15 ++++++++++++--- 4 files changed, 37 insertions(+), 12 deletions(-) diff --git a/qa/rpc-tests/wallet_import_export.py b/qa/rpc-tests/wallet_import_export.py index 355c16d05..8169e36ba 100755 --- a/qa/rpc-tests/wallet_import_export.py +++ b/qa/rpc-tests/wallet_import_export.py @@ -4,7 +4,7 @@ # 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 +from test_framework.util import assert_equal, assert_true, start_nodes class WalletImportExportTest (BitcoinTestFramework): def setup_network(self, split=False): @@ -18,6 +18,9 @@ class WalletImportExportTest (BitcoinTestFramework): # node 0 should have the keys dump_path0 = self.nodes[0].z_exportwallet('walletdump') (t_keys0, sprout_keys0, sapling_keys0) = parse_wallet_file(dump_path0) + + for sapling_key0 in sapling_keys0.splitlines(): + assert_equal(4, len(sapling_key0.split(' #')[0].split()), "Should have 4 parameters before ' #'") assert_true(sprout_address0 in sprout_keys0) assert_true(sapling_address0 in sapling_keys0) @@ -39,6 +42,10 @@ class WalletImportExportTest (BitcoinTestFramework): assert_true(sprout_address0 in sprout_keys1) assert_true(sapling_address0 in sapling_keys1) + # make sure we have perserved the metadata + for sapling_key0 in sapling_keys0.splitlines(): + assert_true(sapling_key0 in sapling_keys1) + # Helper functions def parse_wallet_file(dump_path): file_lines = open(dump_path, "r").readlines() @@ -60,7 +67,7 @@ def parse_wallet_file_lines(file_lines, i): 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) + return ("\n".join(keys), i) if __name__ == '__main__': WalletImportExportTest().main() \ No newline at end of file diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp index 446f3bc41..e6bd0fe3e 100644 --- a/src/wallet/rpcdump.cpp +++ b/src/wallet/rpcdump.cpp @@ -298,9 +298,11 @@ UniValue importwallet_impl(const UniValue& params, bool fHelp, bool fImportZKeys if (fImportZKeys) { auto spendingkey = DecodeSpendingKey(vstr[0]); int64_t nTime = DecodeDumpTime(vstr[1]); + boost::optional hdKeypath = (vstr.size() > 2) ? boost::optional(vstr[2]) : boost::none; + boost::optional seedFpStr = (vstr.size() > 3) ? boost::optional(vstr[3]) : boost::none; if (IsValidSpendingKey(spendingkey)) { auto addResult = boost::apply_visitor( - AddSpendingKeyToWallet(pwalletMain, Params().GetConsensus(), nTime, true), spendingkey); + AddSpendingKeyToWallet(pwalletMain, Params().GetConsensus(), nTime, hdKeypath, seedFpStr, true), spendingkey); if (addResult == KeyAlreadyExists){ LogPrint("zrpc", "Skipping import of zaddr (key already present)\n"); } else if (addResult == KeyNotAdded) { @@ -548,8 +550,9 @@ UniValue dumpwallet_impl(const UniValue& params, bool fHelp, bool fDumpZKeys) 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)); + CKeyMetadata keyMeta = pwalletMain->mapSaplingZKeyMetadata[ivk]; + std::string strTime = EncodeDumpTime(keyMeta.nCreateTime); + file << strprintf("%s %s %s %s # zaddr=%s\n", EncodeSpendingKey(extsk), strTime, keyMeta.hdKeypath, keyMeta.seedFp.GetHex(), EncodePaymentAddress(addr)); } } file << "\n"; @@ -633,8 +636,7 @@ UniValue z_importkey(const UniValue& params, bool fHelp) } // Sapling support - auto addResult = boost::apply_visitor( - AddSpendingKeyToWallet(pwalletMain, Params().GetConsensus()), spendingkey); + auto addResult = boost::apply_visitor(AddSpendingKeyToWallet(pwalletMain, Params().GetConsensus()), spendingkey); if (addResult == KeyAlreadyExists && fIgnoreExistingKey) { return NullUniValue; } diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index be1b27036..6e2631db3 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -4573,7 +4573,7 @@ boost::optional GetSpendingKeyForPaymentAddress::operator } SpendingKeyAddResult AddSpendingKeyToWallet::operator()(const libzcash::SproutSpendingKey &sk) const { - auto addr = sk.address(); + auto addr = sk.address(); if (log){ LogPrint("zrpc", "Importing zaddr %s...\n", EncodePaymentAddress(addr)); } @@ -4610,7 +4610,14 @@ SpendingKeyAddResult AddSpendingKeyToWallet::operator()(const libzcash::SaplingE // 154051200 seconds from epoch is Friday, 26 October 2018 00:00:00 GMT - definitely before Sapling activates m_wallet->mapSaplingZKeyMetadata[ivk].nCreateTime = std::max((int64_t) 154051200, nTime); } - + if (hdKeypath) { + m_wallet->mapSaplingZKeyMetadata[ivk].hdKeypath = hdKeypath.get(); + } + if (seedFpStr) { + uint256 seedFp; + seedFp.SetHex(seedFpStr.get()); + m_wallet->mapSaplingZKeyMetadata[ivk].seedFp = seedFp; + } return KeyAdded; } } diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 5b2d6731d..50acb2394 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -1388,12 +1388,21 @@ private: CWallet *m_wallet; const Consensus::Params ¶ms; int64_t nTime; + boost::optional hdKeypath; // currently sapling only + boost::optional seedFpStr; // currently sapling only bool log; public: AddSpendingKeyToWallet(CWallet *wallet, const Consensus::Params ¶ms) : - m_wallet(wallet), params(params), nTime(1), log(false) {} - AddSpendingKeyToWallet(CWallet *wallet, const Consensus::Params ¶ms, int64_t _nTime, bool _log) : - m_wallet(wallet), params(params), nTime(_nTime), log(_log) {} + m_wallet(wallet), params(params), nTime(1), hdKeypath(boost::none), seedFpStr(boost::none), log(false) {} + AddSpendingKeyToWallet( + CWallet *wallet, + const Consensus::Params ¶ms, + int64_t _nTime, + boost::optional _hdKeypath, + boost::optional _seedFp, + bool _log + ) : m_wallet(wallet), params(params), nTime(_nTime), hdKeypath(_hdKeypath), seedFpStr(_seedFp), log(_log) {} + SpendingKeyAddResult operator()(const libzcash::SproutSpendingKey &sk) const; SpendingKeyAddResult operator()(const libzcash::SaplingExtendedSpendingKey &sk) const;