Add Orchard to default UA receiver types

We also add Orchard-specific information to several RPCs in order for
tests to pass:

- `z_listunifiedreceivers`
- `z_getbalanceforaccount`
- `z_getbalanceforviewingkey`
This commit is contained in:
Jack Grigg 2022-02-23 10:04:34 +00:00
parent 235fde5193
commit b0769e3f1d
6 changed files with 57 additions and 9 deletions

View File

@ -55,7 +55,7 @@ class WalletAccountsTest(BitcoinTestFramework):
# Generate the first address for account 0.
addr0 = self.nodes[0].z_getaddressforaccount(0)
assert_equal(addr0['account'], 0)
assert_equal(set(addr0['pools']), set(['transparent', 'sapling']))
assert_equal(set(addr0['pools']), set(['transparent', 'sapling', 'orchard']))
ua0 = addr0['unifiedaddress']
# We pick mnemonic phrases to ensure that we can always generate the default
@ -70,16 +70,38 @@ class WalletAccountsTest(BitcoinTestFramework):
'no address at diversifier index 0',
self.nodes[0].z_getaddressforaccount, 0, [], 0)
# The second address for account 0 is different to the first address.
addr0_2 = self.nodes[0].z_getaddressforaccount(0)
assert_equal(addr0_2['account'], 0)
assert_equal(set(addr0_2['pools']), set(['transparent', 'sapling', 'orchard']))
ua0_2 = addr0_2['unifiedaddress']
assert(ua0 != ua0_2)
# We can generate a fully-shielded address.
addr0_3 = self.nodes[0].z_getaddressforaccount(0, ['sapling', 'orchard'])
assert_equal(addr0_3['account'], 0)
assert_equal(set(addr0_3['pools']), set(['sapling', 'orchard']))
ua0_3 = addr0_3['unifiedaddress']
# We can generate an address without a Sapling receiver.
addr0_4 = self.nodes[0].z_getaddressforaccount(0, ['transparent', 'orchard'])
assert_equal(addr0_4['account'], 0)
assert_equal(set(addr0_4['pools']), set(['transparent', 'orchard']))
ua0_4 = addr0_4['unifiedaddress']
# The first address for account 1 is different to account 0.
addr1 = self.nodes[0].z_getaddressforaccount(1)
assert_equal(addr1['account'], 1)
assert_equal(set(addr1['pools']), set(['transparent', 'sapling']))
assert_equal(set(addr1['pools']), set(['transparent', 'sapling', 'orchard']))
ua1 = addr1['unifiedaddress']
assert(ua0 != ua1)
# The UA contains the expected receiver kinds.
self.check_receiver_types(ua0, ['transparent', 'sapling'])
self.check_receiver_types(ua1, ['transparent', 'sapling'])
self.check_receiver_types(ua0, ['transparent', 'sapling', 'orchard'])
self.check_receiver_types(ua0_2, ['transparent', 'sapling', 'orchard'])
self.check_receiver_types(ua0_3, [ 'sapling', 'orchard'])
self.check_receiver_types(ua0_4, ['transparent', 'orchard'])
self.check_receiver_types(ua1, ['transparent', 'sapling', 'orchard'])
# The balances of the accounts are all zero.
self.check_balance(0, 0, ua0, {})

View File

@ -381,9 +381,10 @@ class ListReceivedTest (BitcoinTestFramework):
r = node.z_getaddressforaccount(account)
unified_addr = r['unifiedaddress']
receivers = node.z_listunifiedreceivers(unified_addr)
assert_equal(len(receivers), 2)
assert_equal(len(receivers), 3)
assert 'transparent' in receivers
assert 'sapling' in receivers
assert 'orchard' in receivers
# Wallet contains no notes
r = node.z_listreceivedbyaddress(unified_addr, 0)
assert_equal(len(r), 0, "unified_addr should have received zero notes")

View File

@ -3119,14 +3119,16 @@ UniValue z_getaddressforaccount(const UniValue& params, bool fHelp)
receivers.insert(ReceiverType::P2PKH);
} else if (p == "sapling") {
receivers.insert(ReceiverType::Sapling);
} else if (p == "orchard") {
receivers.insert(ReceiverType::Orchard);
} else {
throw JSONRPCError(RPC_INVALID_PARAMETER, "pool arguments must be \"transparent\", or \"sapling\"");
throw JSONRPCError(RPC_INVALID_PARAMETER, "pool arguments must be \"transparent\", \"sapling\", or \"orchard\"");
}
}
}
if (receivers.empty()) {
// Default is the best and second-best shielded pools, and the transparent pool.
receivers = {ReceiverType::P2PKH, ReceiverType::Sapling};
receivers = {ReceiverType::P2PKH, ReceiverType::Sapling, ReceiverType::Orchard};
}
std::optional<libzcash::diversifier_index_t> j = std::nullopt;
@ -3220,6 +3222,9 @@ UniValue z_getaddressforaccount(const UniValue& params, bool fHelp)
case ReceiverType::Sapling:
pools.push_back("sapling");
break;
case ReceiverType::Orchard:
pools.push_back("orchard");
break;
default:
// Unreachable
assert(false);
@ -3331,6 +3336,12 @@ UniValue z_listunifiedreceivers(const UniValue& params, bool fHelp)
UniValue result(UniValue::VOBJ);
for (const auto& receiver : ua) {
std::visit(match {
[&](const libzcash::OrchardRawAddress& addr) {
// Create a single-receiver UA that just contains this Orchard receiver.
UnifiedAddress singleReceiver;
singleReceiver.AddReceiver(addr);
result.pushKV("orchard", keyIO.EncodePaymentAddress(singleReceiver));
},
[&](const libzcash::SaplingPaymentAddress& addr) {
result.pushKV("sapling", keyIO.EncodePaymentAddress(addr));
},
@ -3762,6 +3773,7 @@ UniValue z_getbalanceforviewingkey(const UniValue& params, bool fHelp)
CAmount transparentBalance = 0;
CAmount sproutBalance = 0;
CAmount saplingBalance = 0;
CAmount orchardBalance = 0;
for (const auto& t : spendableInputs.utxos) {
transparentBalance += t.Value();
}
@ -3771,6 +3783,9 @@ UniValue z_getbalanceforviewingkey(const UniValue& params, bool fHelp)
for (const auto& t : spendableInputs.saplingNoteEntries) {
saplingBalance += t.note.value();
}
for (const auto& t : spendableInputs.orchardNoteMetadata) {
orchardBalance += t.GetNoteValue();
}
UniValue pools(UniValue::VOBJ);
auto renderBalance = [&](std::string poolName, CAmount balance) {
@ -3783,6 +3798,7 @@ UniValue z_getbalanceforviewingkey(const UniValue& params, bool fHelp)
renderBalance("transparent", transparentBalance);
renderBalance("sprout", sproutBalance);
renderBalance("sapling", saplingBalance);
renderBalance("orchard", orchardBalance);
UniValue result(UniValue::VOBJ);
result.pushKV("pools", pools);
@ -3863,12 +3879,16 @@ UniValue z_getbalanceforaccount(const UniValue& params, bool fHelp)
CAmount transparentBalance = 0;
CAmount saplingBalance = 0;
CAmount orchardBalance = 0;
for (const auto& t : spendableInputs.utxos) {
transparentBalance += t.Value();
}
for (const auto& t : spendableInputs.saplingNoteEntries) {
saplingBalance += t.note.value();
}
for (const auto& t : spendableInputs.orchardNoteMetadata) {
orchardBalance += t.GetNoteValue();
}
UniValue pools(UniValue::VOBJ);
auto renderBalance = [&](std::string poolName, CAmount balance) {
@ -3880,6 +3900,7 @@ UniValue z_getbalanceforaccount(const UniValue& params, bool fHelp)
};
renderBalance("transparent", transparentBalance);
renderBalance("sapling", saplingBalance);
renderBalance("orchard", orchardBalance);
UniValue result(UniValue::VOBJ);
result.pushKV("pools", pools);

View File

@ -605,7 +605,7 @@ std::optional<libzcash::ZcashdUnifiedSpendingKey>
// when the user calls z_getaddressforaccount.
auto orchardInternalFvk = orchardSk.ToFullViewingKey().ToInternalIncomingViewingKey();
if (!AddOrchardRawAddress(orchardInternalFvk, orchardInternalFvk.Address(0))) {
throw std::runtime_error("CWallet::GenerateUnifiedSpendingKeyForAccount(): Failed to add Sapling change address to the wallet.");
throw std::runtime_error("CWallet::GenerateUnifiedSpendingKeyForAccount(): Failed to add Orchard change address to the wallet.");
};
auto zufvk = ZcashdUnifiedFullViewingKey::FromUnifiedFullViewingKey(Params(), ufvk);

View File

@ -794,6 +794,7 @@ public:
std::vector<COutput> utxos;
std::vector<SproutNoteEntry> sproutNoteEntries;
std::vector<SaplingNoteEntry> saplingNoteEntries;
std::vector<OrchardNoteMetadata> orchardNoteMetadata;
/**
* Selectively discard notes that are not required to obtain the desired
@ -816,6 +817,9 @@ public:
for (const auto& t : saplingNoteEntries) {
result += t.note.value();
}
for (const auto& t : orchardNoteMetadata) {
result += t.GetNoteValue();
}
return result;
}

View File

@ -150,7 +150,7 @@ UnifiedAddressGenerationResult ZcashdUnifiedFullViewingKey::FindAddress(
UnifiedAddressGenerationResult ZcashdUnifiedFullViewingKey::FindAddress(
const diversifier_index_t& j) const {
return FindAddress(j, {ReceiverType::P2PKH, ReceiverType::Sapling});
return FindAddress(j, {ReceiverType::P2PKH, ReceiverType::Sapling, ReceiverType::Orchard});
}
std::optional<RecipientAddress> ZcashdUnifiedFullViewingKey::GetChangeAddress(const ChangeRequest& req) const {