diff --git a/qa/rpc-tests/wallet_changeindicator.py b/qa/rpc-tests/wallet_changeindicator.py index 58b431fc2..d26381064 100755 --- a/qa/rpc-tests/wallet_changeindicator.py +++ b/qa/rpc-tests/wallet_changeindicator.py @@ -60,5 +60,18 @@ class WalletChangeIndicatorTest (BitcoinTestFramework): assert_equal(Decimal('0.6'), sortedunspent[1]['amount']) assert_false(sortedunspent[1]['change'], "Unspent note valued at 0.6 should not be change") + # Give node 0 a viewing key + viewing_key = self.nodes[1].z_exportviewingkey(zaddr1) + self.nodes[0].z_importviewingkey(viewing_key) + received_node0 = self.nodes[0].z_listreceivedbyaddress(zaddr1, 0) + assert_equal(2, len(received_node0)) + unspent_node0 = self.nodes[0].z_listunspent(1, 9999999, True) + assert_equal(2, len(unspent_node0)) + # node 0 only has a viewing key so does not see the change field + assert_false('change' in received_node0[0]) + assert_false('change' in received_node0[1]) + assert_false('change' in unspent_node0[0]) + assert_false('change' in unspent_node0[1]) + if __name__ == '__main__': WalletChangeIndicatorTest().main() diff --git a/qa/rpc-tests/wallet_nullifiers.py b/qa/rpc-tests/wallet_nullifiers.py index db8940d3b..72e26fab8 100755 --- a/qa/rpc-tests/wallet_nullifiers.py +++ b/qa/rpc-tests/wallet_nullifiers.py @@ -5,7 +5,7 @@ from test_framework.test_framework import BitcoinTestFramework -from test_framework.util import assert_equal, start_node, \ +from test_framework.util import assert_equal, assert_true, start_node, \ start_nodes, connect_nodes_bi, bitcoind_processes import time @@ -189,7 +189,7 @@ class WalletNullifiersTest (BitcoinTestFramework): assert_equal(myzaddr in self.nodes[3].z_listaddresses(True), True) # Node 3 should see the same received notes as node 2; however, - # some of the notes were change for note 2 but not for note 3. + # some of the notes were change for node 2 but not for node 3. # Aside from that the recieved notes should be the same. So, # group by txid and then check that all properties aside from # change are equal. @@ -199,7 +199,8 @@ class WalletNullifiersTest (BitcoinTestFramework): for txid in node2Received: received2 = node2Received[txid] received3 = node3Received[txid] - assert_equal(len(received2), len(received3)) + # the change field will be omitted for received3, but all other fields should be shared + assert_true(len(received2) >= len(received3)) for key in received2: # check all the properties except for change if key != 'change': diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index e93781636..0d7861aa2 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -2565,12 +2565,15 @@ UniValue z_listunspent(const UniValue& params, bool fHelp) obj.push_back(Pair("jsindex", (int)entry.jsop.js )); obj.push_back(Pair("jsoutindex", (int)entry.jsop.n)); obj.push_back(Pair("confirmations", entry.nHeight)); - obj.push_back(Pair("spendable", pwalletMain->HaveSproutSpendingKey(boost::get(entry.address)))); + bool hasSproutSpendingKey = pwalletMain->HaveSproutSpendingKey(boost::get(entry.address)); + obj.push_back(Pair("spendable", hasSproutSpendingKey)); obj.push_back(Pair("address", EncodePaymentAddress(entry.address))); obj.push_back(Pair("amount", ValueFromAmount(CAmount(entry.plaintext.value())))); std::string data(entry.plaintext.memo().begin(), entry.plaintext.memo().end()); obj.push_back(Pair("memo", HexStr(data))); - obj.push_back(Pair("change", pwalletMain->IsNoteChange(nullifierSet, entry.address, entry.jsop))); + if (hasSproutSpendingKey) { + obj.push_back(Pair("change", pwalletMain->IsNoteChange(nullifierSet, entry.address, entry.jsop))); + } results.push_back(obj); } } @@ -3296,15 +3299,15 @@ UniValue z_listreceivedbyaddress(const UniValue& params, bool fHelp) assert(boost::get(&zaddr) != nullptr); auto sproutzaddr = boost::get(zaddr); - if (!(pwalletMain->HaveSproutSpendingKey(sproutzaddr) || pwalletMain->HaveSproutViewingKey(sproutzaddr))) { + bool hasSproutSpendingKey = pwalletMain->HaveSproutSpendingKey(sproutzaddr); + if (!(hasSproutSpendingKey || pwalletMain->HaveSproutViewingKey(sproutzaddr))) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "From address does not belong to this node, zaddr spending key or viewing key not found."); } - UniValue result(UniValue::VARR); std::vector entries; pwalletMain->GetFilteredNotes(entries, fromaddress, nMinDepth, false, false); - std::set> nullifierSet = pwalletMain->GetNullifiersForAddresses({zaddr}); + auto nullifierSet = hasSproutSpendingKey ? pwalletMain->GetNullifiersForAddresses({zaddr}) : std::set>(); for (CSproutNotePlaintextEntry & entry : entries) { UniValue obj(UniValue::VOBJ); obj.push_back(Pair("txid", entry.jsop.hash.ToString())); @@ -3314,7 +3317,9 @@ UniValue z_listreceivedbyaddress(const UniValue& params, bool fHelp) // (txid, jsindex, jsoutindex) is needed to globally identify a note obj.push_back(Pair("jsindex", entry.jsop.js)); obj.push_back(Pair("jsoutindex", entry.jsop.n)); - obj.push_back(Pair("change", pwalletMain->IsNoteChange(nullifierSet, entry.address, entry.jsop))); + if (hasSproutSpendingKey) { + obj.push_back(Pair("change", pwalletMain->IsNoteChange(nullifierSet, entry.address, entry.jsop))); + } result.push_back(obj); } return result;