Skip to content

Commit

Permalink
Merge pull request jl777#263 from Asherda/viewing_keys_backports
Browse files Browse the repository at this point in the history
Viewing keys backports
  • Loading branch information
miketout authored Sep 7, 2024
2 parents 6bdf137 + d9d879b commit a91c3d9
Show file tree
Hide file tree
Showing 39 changed files with 924 additions and 1,395 deletions.
8 changes: 6 additions & 2 deletions qa/rpc-tests/wallet_nullifiers.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,10 +124,14 @@ def run_test (self):
'total': node3mined + zsendmany2notevalue,
})

# add node 1 address and node 2 viewing key to node 3
# Add node 1 address and node 2 viewing key to node 3
myzvkey = self.nodes[2].z_exportviewingkey(myzaddr)
self.nodes[3].importaddress(mytaddr1)
self.nodes[3].z_importviewingkey(myzvkey, 'whenkeyisnew', 1)
importvk_result = self.nodes[3].z_importviewingkey(myzvkey, 'whenkeyisnew', 1)

# Check results of z_importviewingkey
assert_equal(importvk_result["type"], "sprout")
assert_equal(importvk_result["address"], myzaddr)

# Check the address has been imported
assert_equal(myzaddr in self.nodes[3].z_listaddresses(), False)
Expand Down
19 changes: 13 additions & 6 deletions qa/rpc-tests/wallet_persistence.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,13 @@ class WalletPersistenceTest (BitcoinTestFramework):

def setup_chain(self):
print("Initializing test directory " + self.options.tmpdir)
initialize_chain_clean(self.options.tmpdir, 3)
initialize_chain_clean(self.options.tmpdir, 4)

def setup_network(self, split=False):
self.nodes = start_nodes(3, self.options.tmpdir,
extra_args=[[
'-nuparams=5ba81b19:100', # Overwinter
'-nuparams=76b809bb:201', # Sapling
]] * 3)
self.nodes = start_nodes(4, self.options.tmpdir)
connect_nodes_bi(self.nodes,0,1)
connect_nodes_bi(self.nodes,1,2)
connect_nodes_bi(self.nodes,2,3)
self.is_network_split=False
self.sync_all()

Expand Down Expand Up @@ -116,6 +113,13 @@ def run_test(self):
self.nodes[2].z_importkey(sk0, "yes")
assert_equal(self.nodes[2].z_getbalance(sapling_addr), Decimal('5'))

# Verify importing a viewing key will update and persist the nullifiers and witnesses correctly
extfvk0 = self.nodes[0].z_exportviewingkey(sapling_addr)
self.nodes[3].z_importviewingkey(extfvk0, "yes")
assert_equal(self.nodes[3].z_getbalance(sapling_addr), Decimal('5'))
assert_equal(self.nodes[3].z_gettotalbalance()['private'], '0.00')
assert_equal(self.nodes[3].z_gettotalbalance(1, True)['private'], '5.00')

# Restart the nodes
stop_nodes(self.nodes)
wait_bitcoinds()
Expand All @@ -125,6 +129,9 @@ def run_test(self):
# Prior to PR #3590, there will be an error as spent notes are considered unspent:
# Assertion failed: expected: <25.00000000> but was: <5>
assert_equal(self.nodes[2].z_getbalance(sapling_addr), Decimal('5'))
assert_equal(self.nodes[3].z_getbalance(sapling_addr), Decimal('5'))
assert_equal(self.nodes[3].z_gettotalbalance()['private'], '0.00')
assert_equal(self.nodes[3].z_gettotalbalance(1, True)['private'], '5.00')

# Verity witnesses persisted correctly by sending shielded funds
recipients = []
Expand Down
28 changes: 24 additions & 4 deletions qa/rpc-tests/wallet_sapling.py
Original file line number Diff line number Diff line change
Expand Up @@ -186,11 +186,31 @@ def run_test(self):

# 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(saplingAddrInfo0["address"], saplingAddr0)
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(saplingAddrInfo1["address"], saplingAddr1)
assert_equal(self.nodes[2].z_getbalance(saplingAddrInfo1["address"]), Decimal('5'))

# Verify importing a viewing key will update the nullifiers and witnesses correctly
extfvk0 = self.nodes[0].z_exportviewingkey(saplingAddr0)
saplingAddrInfo0 = self.nodes[3].z_importviewingkey(extfvk0, "yes")
assert_equal(saplingAddrInfo0["type"], "sapling")
assert_equal(saplingAddrInfo0["address"], saplingAddr0)
assert_equal(self.nodes[3].z_getbalance(saplingAddrInfo0["address"]), Decimal('10'))
extfvk1 = self.nodes[1].z_exportviewingkey(saplingAddr1)
saplingAddrInfo1 = self.nodes[3].z_importviewingkey(extfvk1, "yes")
assert_equal(saplingAddrInfo1["type"], "sapling")
assert_equal(saplingAddrInfo1["address"], saplingAddr1)
assert_equal(self.nodes[3].z_getbalance(saplingAddrInfo1["address"]), Decimal('5'))

# Verify that z_gettotalbalance only includes watch-only addresses when requested
assert_equal(self.nodes[3].z_gettotalbalance()['private'], '0.00')
assert_equal(self.nodes[3].z_gettotalbalance(1, True)['private'], '15.00')

# Make sure we get a useful error when trying to send to both sprout and sapling
node4_sproutaddr = self.nodes[3].z_getnewaddress('sprout')
Expand Down
31 changes: 13 additions & 18 deletions qa/rpc-tests/zkey_import_export.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,11 +74,6 @@ def get_private_balance(node):
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()
Expand Down Expand Up @@ -122,27 +117,28 @@ def find_imported_key(node, import_zaddr):

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)
Expand All @@ -158,12 +154,11 @@ def find_imported_key(node, import_zaddr):
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()
22 changes: 10 additions & 12 deletions src/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -130,16 +130,15 @@ LIBZCASH_H = \
zcash/IncrementalMerkleTree.hpp \
zcash/NoteEncryption.hpp \
zcash/Address.hpp \
zcash/address/sapling.hpp \
zcash/address/sprout.hpp \
zcash/address/zip32.h \
zcash/JoinSplit.hpp \
zcash/Note.hpp \
zcash/prf.h \
zcash/Proof.hpp \
zcash/address/sapling.hpp \
zcash/address/sprout.hpp \
zcash/util.h \
zcash/Zcash.h \
zcash/address/zip32.cpp \
zcash/address/zip32.h
zcash/Zcash.h

.PHONY: FORCE check-symbols check-security
# bitcoin core #
Expand Down Expand Up @@ -263,9 +262,9 @@ BITCOIN_CORE_H = \
utiltime.h \
validationinterface.h \
version.h \
wallet/asyncrpcoperation_common.h \
wallet/asyncrpcoperation_mergetoaddress.h \
wallet/asyncrpcoperation_saplingconsolidation.h \
wallet/asyncrpcoperation_sweeptoaddress.h \
wallet/asyncrpcoperation_saplingmigration.h \
wallet/asyncrpcoperation_sendmany.h \
wallet/asyncrpcoperation_shieldcoinbase.h \
wallet/crypter.h \
Expand Down Expand Up @@ -405,8 +404,7 @@ libbitcoin_wallet_a_SOURCES = \
zcbenchmarks.h \
wallet/asyncrpcoperation_common.cpp \
wallet/asyncrpcoperation_mergetoaddress.cpp \
wallet/asyncrpcoperation_saplingconsolidation.cpp \
wallet/asyncrpcoperation_sweeptoaddress.cpp \
wallet/asyncrpcoperation_saplingmigration.cpp \
wallet/asyncrpcoperation_sendmany.cpp \
wallet/asyncrpcoperation_shieldcoinbase.cpp \
wallet/crypter.cpp \
Expand All @@ -421,7 +419,6 @@ libbitcoin_wallet_a_SOURCES = \
wallet/wallet.cpp \
wallet/wallet_ismine.cpp \
wallet/walletdb.cpp \
zcash/address/zip32.cpp \
$(BITCOIN_CORE_H) \
$(LIBZCASH_H)

Expand Down Expand Up @@ -729,12 +726,13 @@ libzcash_a_SOURCES = \
zcash/IncrementalMerkleTree.cpp \
zcash/NoteEncryption.cpp \
zcash/Address.cpp \
zcash/address/sapling.cpp \
zcash/address/sprout.cpp \
zcash/address/zip32.cpp \
zcash/JoinSplit.cpp \
zcash/Proof.cpp \
zcash/Note.cpp \
zcash/prf.cpp \
zcash/address/sapling.cpp \
zcash/address/sprout.cpp \
zcash/util.cpp \
zcash/address/zip32.cpp

Expand Down
15 changes: 14 additions & 1 deletion src/gtest/test_keys.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
#include <chainparams.h>
#include <key_io.h>
#include <zcash/Address.hpp>
#include <zcash/address/zip32.h>
#include "consensus/upgrades.h"

#include "utiltest.h"
Expand Down Expand Up @@ -29,6 +28,20 @@ TEST(Keys, EncodeAndDecodeSapling)
auto sk2 = boost::get<libzcash::SaplingExtendedSpendingKey>(spendingkey2);
EXPECT_EQ(sk, sk2);
}
{
auto extfvk = sk.ToXFVK();
std::string vk_string = EncodeViewingKey(extfvk);
EXPECT_EQ(
vk_string.substr(0, 7),
Params().Bech32HRP(CChainParams::SAPLING_EXTENDED_FVK));

auto viewingkey2 = DecodeViewingKey(vk_string);
EXPECT_TRUE(IsValidViewingKey(viewingkey2));

ASSERT_TRUE(boost::get<libzcash::SaplingExtendedFullViewingKey>(&viewingkey2) != nullptr);
auto extfvk2 = boost::get<libzcash::SaplingExtendedFullViewingKey>(viewingkey2);
EXPECT_EQ(extfvk, extfvk2);
}
{
auto addr = sk.DefaultAddress();

Expand Down
Loading

0 comments on commit a91c3d9

Please sign in to comment.