Auto merge of #4220 - oxarbitrage:issue3748, r=str4d
Return address and type of imported key in z_importkey Fixes #3748.
This commit is contained in:
commit
37435aa2c2
|
@ -136,11 +136,13 @@ class WalletSaplingTest(BitcoinTestFramework):
|
|||
|
||||
# Verify importing a spending key will update the nullifiers and witnesses correctly
|
||||
sk0 = self.nodes[0].z_exportkey(saplingAddr0)
|
||||
self.nodes[2].z_importkey(sk0, "yes")
|
||||
assert_equal(self.nodes[2].z_getbalance(saplingAddr0), Decimal('10'))
|
||||
saplingAddrInfo0 = self.nodes[2].z_importkey(sk0, "yes")
|
||||
assert_equal(saplingAddrInfo0["type"], "sapling")
|
||||
assert_equal(self.nodes[2].z_getbalance(saplingAddrInfo0["address"]), Decimal('10'))
|
||||
sk1 = self.nodes[1].z_exportkey(saplingAddr1)
|
||||
self.nodes[2].z_importkey(sk1, "yes")
|
||||
assert_equal(self.nodes[2].z_getbalance(saplingAddr1), Decimal('5'))
|
||||
saplingAddrInfo1 = self.nodes[2].z_importkey(sk1, "yes")
|
||||
assert_equal(saplingAddrInfo1["type"], "sapling")
|
||||
assert_equal(self.nodes[2].z_getbalance(saplingAddrInfo1["address"]), Decimal('5'))
|
||||
|
||||
# Make sure we get a useful error when trying to send to both sprout and sapling
|
||||
node4_sproutaddr = self.nodes[3].z_getnewaddress('sprout')
|
||||
|
|
|
@ -74,11 +74,6 @@ class ZkeyImportExportTest (BitcoinTestFramework):
|
|||
balance = node.z_gettotalbalance()
|
||||
return balance['private']
|
||||
|
||||
def find_imported_key(node, import_zaddr):
|
||||
zaddrs = node.z_listaddresses()
|
||||
assert(import_zaddr in zaddrs)
|
||||
return import_zaddr
|
||||
|
||||
# Seed Alice with some funds
|
||||
alice.generate(10)
|
||||
self.sync_all()
|
||||
|
@ -122,27 +117,28 @@ class ZkeyImportExportTest (BitcoinTestFramework):
|
|||
|
||||
logging.info("Importing bob_privkey into charlie...")
|
||||
# z_importkey rescan defaults to "whenkeyisnew", so should rescan here
|
||||
charlie.z_importkey(bob_privkey)
|
||||
ipk_zaddr = find_imported_key(charlie, bob_zaddr)
|
||||
ipk_zaddr = charlie.z_importkey(bob_privkey)
|
||||
|
||||
# z_importkey should have rescanned for new key, so this should pass:
|
||||
verify_utxos(charlie, amounts[:4], ipk_zaddr)
|
||||
verify_utxos(charlie, amounts[:4], ipk_zaddr["address"])
|
||||
|
||||
# address is sprout
|
||||
assert_equal(ipk_zaddr["type"], "sprout")
|
||||
|
||||
# Verify idempotent behavior:
|
||||
charlie.z_importkey(bob_privkey)
|
||||
ipk_zaddr2 = find_imported_key(charlie, bob_zaddr)
|
||||
assert_equal(ipk_zaddr, ipk_zaddr2)
|
||||
ipk_zaddr2 = charlie.z_importkey(bob_privkey)
|
||||
assert_equal(ipk_zaddr["address"], ipk_zaddr2["address"])
|
||||
|
||||
# amounts should be unchanged
|
||||
verify_utxos(charlie, amounts[:4], ipk_zaddr2)
|
||||
verify_utxos(charlie, amounts[:4], ipk_zaddr2["address"])
|
||||
|
||||
logging.info("Sending post-import txns...")
|
||||
for amount in amounts[4:]:
|
||||
z_send(alice, alice_zaddr, bob_zaddr, amount)
|
||||
|
||||
verify_utxos(bob, amounts, bob_zaddr)
|
||||
verify_utxos(charlie, amounts, ipk_zaddr)
|
||||
verify_utxos(charlie, amounts, ipk_zaddr2)
|
||||
verify_utxos(charlie, amounts, ipk_zaddr["address"])
|
||||
verify_utxos(charlie, amounts, ipk_zaddr2["address"])
|
||||
|
||||
# keep track of the fees incurred by bob (his sends)
|
||||
bob_fee = Decimal(0)
|
||||
|
@ -158,12 +154,11 @@ class ZkeyImportExportTest (BitcoinTestFramework):
|
|||
assert_equal(bob.z_getbalance(bob_zaddr), bob_balance)
|
||||
|
||||
# z_import onto new node "david" (blockchain rescan, default or True?)
|
||||
david.z_importkey(bob_privkey)
|
||||
d_ipk_zaddr = find_imported_key(david, bob_zaddr)
|
||||
d_ipk_zaddr = david.z_importkey(bob_privkey)
|
||||
|
||||
# Check if amt bob spent is deducted for charlie and david
|
||||
assert_equal(charlie.z_getbalance(ipk_zaddr), bob_balance)
|
||||
assert_equal(david.z_getbalance(d_ipk_zaddr), bob_balance)
|
||||
assert_equal(charlie.z_getbalance(ipk_zaddr["address"]), bob_balance)
|
||||
assert_equal(david.z_getbalance(d_ipk_zaddr["address"]), bob_balance)
|
||||
|
||||
if __name__ == '__main__':
|
||||
ZkeyImportExportTest().main()
|
||||
|
|
|
@ -678,6 +678,11 @@ UniValue z_importkey(const UniValue& params, bool fHelp)
|
|||
"2. rescan (string, optional, default=\"whenkeyisnew\") Rescan the wallet for transactions - can be \"yes\", \"no\" or \"whenkeyisnew\"\n"
|
||||
"3. startHeight (numeric, optional, default=0) Block height to start rescan from\n"
|
||||
"\nNote: This call can take minutes to complete if rescan is true.\n"
|
||||
"\nResult:\n"
|
||||
"{\n"
|
||||
" \"type\" : \"xxxx\", (string) \"sprout\" or \"sapling\"\n"
|
||||
" \"address\" : \"address|DefaultAddress\", (string) The address(sprout) or the DefaultAddress(sapling)\n"
|
||||
"}\n"
|
||||
"\nExamples:\n"
|
||||
"\nExport a zkey\n"
|
||||
+ HelpExampleCli("z_exportkey", "\"myaddress\"") +
|
||||
|
@ -737,10 +742,15 @@ UniValue z_importkey(const UniValue& params, bool fHelp)
|
|||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid spending key");
|
||||
}
|
||||
|
||||
auto addrInfo = boost::apply_visitor(libzcash::AddressInfoFromSpendingKey{}, spendingkey);
|
||||
UniValue result(UniValue::VOBJ);
|
||||
result.pushKV("type", addrInfo.first);
|
||||
result.pushKV("address", EncodePaymentAddress(addrInfo.second));
|
||||
|
||||
// Sapling support
|
||||
auto addResult = boost::apply_visitor(AddSpendingKeyToWallet(pwalletMain, Params().GetConsensus()), spendingkey);
|
||||
if (addResult == KeyAlreadyExists && fIgnoreExistingKey) {
|
||||
return NullUniValue;
|
||||
return result;
|
||||
}
|
||||
pwalletMain->MarkDirty();
|
||||
if (addResult == KeyNotAdded) {
|
||||
|
@ -755,7 +765,7 @@ UniValue z_importkey(const UniValue& params, bool fHelp)
|
|||
pwalletMain->ScanForWalletTransactions(chainActive[nRescanHeight], true);
|
||||
}
|
||||
|
||||
return NullUniValue;
|
||||
return result;
|
||||
}
|
||||
|
||||
UniValue z_importviewingkey(const UniValue& params, bool fHelp)
|
||||
|
|
|
@ -425,6 +425,32 @@ BOOST_AUTO_TEST_CASE(rpc_wallet_z_validateaddress)
|
|||
BOOST_CHECK_EQUAL(find_value(resultObj, "diversifiedtransmissionkey").get_str(), "34ed1f60f5db5763beee1ddbb37dd5f7e541d4d4fbdcc09fbfcc6b8e949bbe9d");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(rpc_wallet_z_importkey_paymentaddress) {
|
||||
SelectParams(CBaseChainParams::MAIN);
|
||||
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||
|
||||
auto testAddress = [](const std::string& type, const std::string& key) {
|
||||
UniValue ret;
|
||||
BOOST_CHECK_NO_THROW(ret = CallRPC("z_importkey " + key));
|
||||
auto defaultAddr = find_value(ret, "address").get_str();
|
||||
BOOST_CHECK_EQUAL(type, find_value(ret, "type").get_str());
|
||||
BOOST_CHECK_NO_THROW(ret = CallRPC("z_validateaddress " + defaultAddr));
|
||||
ret = ret.get_obj();
|
||||
BOOST_CHECK_EQUAL(true, find_value(ret, "isvalid").get_bool());
|
||||
BOOST_CHECK_EQUAL(true, find_value(ret, "ismine").get_bool());
|
||||
BOOST_CHECK_EQUAL(type, find_value(ret, "type").get_str());
|
||||
};
|
||||
|
||||
testAddress("sapling", "secret-extended-key-main1qya4wae0qqqqqqpxfq3ukywunn"
|
||||
"dtr8xf39hktp3w4z94smuu3l8wr6h4cwxklzzemtg9sk5c7tamfqs48ml6rvuvyup8"
|
||||
"ne6jz9g7l0asew0htdpjgfss29et84uvqhynjayl3laphks2wxy3c8vhqr4wrca3wl"
|
||||
"ft2fhcacqtvfwsht4t33l8ckpyr8djmzj7swlvhdhepvc3ehycf9cja335ex6rlpka"
|
||||
"8z2gzkul3mztga2ups55c3xvn9j6vpdfm5a5v60g9v3sztcpvxqhm");
|
||||
|
||||
testAddress("sprout",
|
||||
"SKxoWv77WGwFnUJitQKNEcD636bL4X5Gd6wWmgaA4Q9x8jZBPJXT");
|
||||
}
|
||||
|
||||
/*
|
||||
* This test covers RPC command z_exportwallet
|
||||
*/
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include "hash.h"
|
||||
#include "prf.h"
|
||||
#include "streams.h"
|
||||
#include "zcash/zip32.h"
|
||||
|
||||
#include <librustzcash.h>
|
||||
|
||||
|
@ -109,6 +110,16 @@ SaplingPaymentAddress SaplingSpendingKey::default_address() const {
|
|||
return addrOpt.value();
|
||||
}
|
||||
|
||||
std::pair<std::string, PaymentAddress> AddressInfoFromSpendingKey::operator()(const SproutSpendingKey &sk) const {
|
||||
return std::make_pair("sprout", sk.address());
|
||||
}
|
||||
std::pair<std::string, PaymentAddress> AddressInfoFromSpendingKey::operator()(const SaplingExtendedSpendingKey &sk) const {
|
||||
return std::make_pair("sapling", sk.DefaultAddress());
|
||||
}
|
||||
std::pair<std::string, PaymentAddress> AddressInfoFromSpendingKey::operator()(const InvalidEncoding&) const {
|
||||
throw std::invalid_argument("Cannot derive default address from invalid spending key");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool IsValidPaymentAddress(const libzcash::PaymentAddress& zaddr) {
|
||||
|
|
|
@ -221,6 +221,13 @@ public:
|
|||
typedef boost::variant<InvalidEncoding, SproutPaymentAddress, SaplingPaymentAddress> PaymentAddress;
|
||||
typedef boost::variant<InvalidEncoding, SproutViewingKey> ViewingKey;
|
||||
|
||||
class AddressInfoFromSpendingKey : public boost::static_visitor<std::pair<std::string, PaymentAddress>> {
|
||||
public:
|
||||
std::pair<std::string, PaymentAddress> operator()(const SproutSpendingKey&) const;
|
||||
std::pair<std::string, PaymentAddress> operator()(const struct SaplingExtendedSpendingKey&) const;
|
||||
std::pair<std::string, PaymentAddress> operator()(const InvalidEncoding&) const;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
/** Check whether a PaymentAddress is not an InvalidEncoding. */
|
||||
|
|
Loading…
Reference in New Issue