z_sendmany: Expand `privacyPolicy` cases

We now have a full roster of privacy policies. We can graph the
relationships between the policies; arrows point from more-private to
less-private, and each policy is permitted to reveal information covered
by all policies pointing to it (in addition to the extra information it
is permitted to reveal).

                       FullPrivacy
                            v
                   AllowRevealedAmounts
                        v           v
    AllowRevealedRecipients   ---- AllowRevealedSenders
               v             /               v
     AllowFullyTransparent <-  AllowLinkingAccountAddresses
                        v       v
                        NoPrivacy

The synthetic `LegacyCompat` policy now uses the `AllowFullyTransparent`
policy for backwards compatibility, and the `FullPrivacy` policy if the
sender or recipients involve Unified Addresses.

Closes zcash/zcash#5677.
Closes zcash/zcash#5678.
This commit is contained in:
Jack Grigg 2022-03-17 04:00:48 +00:00
parent 1505121877
commit 65cb79e023
10 changed files with 297 additions and 20 deletions

View File

@ -88,7 +88,8 @@ Wallet
information than the given strategy permits, `z_sendmany` will return an
error. The parameter defaults to `LegacyCompat`, which applies the most
restrictive strategy `FullPrivacy` when a Unified Address is present as the
sender or a recipient, and otherwise preserves existing behaviour.
sender or a recipient, and otherwise preserves existing behaviour (which
corresponds to the `AllowFullyTransparent` policy).
- Since Sprout outputs are no longer created (with the exception of change)
'z_sendmany' no longer generates payment disclosures (which were only

View File

@ -70,7 +70,7 @@ class OrchardReorgTest(BitcoinTestFramework):
# Create an Orchard note.
recipients = [{'address': ua, 'amount': Decimal('12.5')}]
opid = self.nodes[0].z_sendmany(get_coinbase_address(self.nodes[0]), recipients, 1, 0)
opid = self.nodes[0].z_sendmany(get_coinbase_address(self.nodes[0]), recipients, 1, 0, 'AllowRevealedSenders')
wait_and_assert_operationid_status(self.nodes[0], opid)
# After mining a block, finalorchardroot should have changed.
@ -95,7 +95,7 @@ class OrchardReorgTest(BitcoinTestFramework):
# Create another Orchard note on node 0.
recipients = [{'address': ua, 'amount': Decimal('12.5')}]
opid = self.nodes[0].z_sendmany(get_coinbase_address(self.nodes[0]), recipients, 1, 0)
opid = self.nodes[0].z_sendmany(get_coinbase_address(self.nodes[0]), recipients, 1, 0, 'AllowRevealedSenders')
wait_and_assert_operationid_status(self.nodes[0], opid)
# Mine two blocks on node 0.

View File

@ -118,7 +118,7 @@ class WalletAccountsTest(BitcoinTestFramework):
# Send coinbase funds to the UA.
print('Sending coinbase funds to account')
recipients = [{'address': ua0, 'amount': Decimal('10')}]
opid = self.nodes[0].z_sendmany(get_coinbase_address(self.nodes[0]), recipients, 1, 0)
opid = self.nodes[0].z_sendmany(get_coinbase_address(self.nodes[0]), recipients, 1, 0, 'AllowRevealedSenders')
txid = wait_and_assert_operationid_status(self.nodes[0], opid)
# The wallet should detect the new note as belonging to the UA.
@ -169,7 +169,7 @@ class WalletAccountsTest(BitcoinTestFramework):
# Send more coinbase funds to the UA.
print('Sending coinbase funds to account')
recipients = [{'address': ua0, 'amount': Decimal('10')}]
opid = self.nodes[0].z_sendmany(get_coinbase_address(self.nodes[0]), recipients, 1, 0)
opid = self.nodes[0].z_sendmany(get_coinbase_address(self.nodes[0]), recipients, 1, 0, 'AllowRevealedSenders')
txid = wait_and_assert_operationid_status(self.nodes[0], opid)
# The wallet should detect the new note as belonging to the UA.

View File

@ -54,7 +54,7 @@ class WalletOrchardTest(BitcoinTestFramework):
saplingAddr2 = self.nodes[2].z_listunifiedreceivers(ua2)['sapling']
recipients = [{"address": saplingAddr2, "amount": Decimal('10')}]
myopid = self.nodes[0].z_sendmany(get_coinbase_address(self.nodes[0]), recipients, 1, 0)
myopid = self.nodes[0].z_sendmany(get_coinbase_address(self.nodes[0]), recipients, 1, 0, 'AllowRevealedSenders')
wait_and_assert_operationid_status(self.nodes[0], myopid)
# Mine the tx & activate NU5
@ -70,7 +70,7 @@ class WalletOrchardTest(BitcoinTestFramework):
# Node 0 shields some funds
# t-coinbase -> Orchard
recipients = [{"address": ua1, "amount": Decimal('10')}]
myopid = self.nodes[0].z_sendmany(get_coinbase_address(self.nodes[0]), recipients, 1, 0)
myopid = self.nodes[0].z_sendmany(get_coinbase_address(self.nodes[0]), recipients, 1, 0, 'AllowRevealedSenders')
wait_and_assert_operationid_status(self.nodes[0], myopid)
self.sync_all()
@ -86,7 +86,7 @@ class WalletOrchardTest(BitcoinTestFramework):
# Send another tx to ua1
recipients = [{"address": ua1, "amount": Decimal('10')}]
myopid = self.nodes[0].z_sendmany(get_coinbase_address(self.nodes[0]), recipients, 1, 0)
myopid = self.nodes[0].z_sendmany(get_coinbase_address(self.nodes[0]), recipients, 1, 0, 'AllowRevealedSenders')
wait_and_assert_operationid_status(self.nodes[0], myopid)
# Mine the tx & generate a majority chain on the 0/1 side of the split

View File

@ -4,8 +4,15 @@
# file COPYING or https://www.opensource.org/licenses/mit-license.php .
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal, assert_greater_than, connect_nodes_bi, \
DEFAULT_FEE, start_nodes, wait_and_assert_operationid_status
from test_framework.util import (
assert_equal,
assert_greater_than,
assert_raises_message,
connect_nodes_bi,
DEFAULT_FEE,
start_nodes,
wait_and_assert_operationid_status,
)
from test_framework.authproxy import JSONRPCException
from test_framework.mininode import COIN
from decimal import Decimal
@ -164,9 +171,36 @@ class WalletZSendmanyTest(BitcoinTestFramework):
# Change went to a fresh address, so use `ANY_TADDR` which
# should hold the rest of our transparent funds.
source = 'ANY_TADDR'
recipients = []
recipients.append({"address":n0ua0, "amount":10})
opid = self.nodes[2].z_sendmany('ANY_TADDR', recipients, 1, 0)
# If we attempt to spend with the default privacy policy, z_sendmany
# fails because it needs to spend transparent coins in a transaction
# involving a Unified Address.
revealed_senders_msg = 'This transaction requires selecting transparent coins, which is not enabled by default because it will publicly reveal transaction senders and amounts. THIS MAY AFFECT YOUR PRIVACY. Resubmit with the `privacyPolicy` parameter set to `AllowRevealedSenders` or weaker if you wish to allow this transaction to proceed anyway.'
opid = self.nodes[2].z_sendmany(source, recipients, 1, 0)
wait_and_assert_operationid_status(self.nodes[2], opid, 'failed', revealed_senders_msg)
# We can't create a transaction with an unknown privacy policy.
assert_raises_message(
JSONRPCException,
'Unknown privacy policy name \'ZcashIsAwesome\'',
self.nodes[2].z_sendmany,
source, recipients, 1, 0, 'ZcashIsAwesome')
# If we set any policy that does not include AllowRevealedSenders,
# z_sendmany also fails.
for policy in [
'FullPrivacy',
'AllowRevealedAmounts',
'AllowRevealedRecipients',
]:
opid = self.nodes[2].z_sendmany(source, recipients, 1, 0, policy)
wait_and_assert_operationid_status(self.nodes[2], opid, 'failed', revealed_senders_msg)
# By setting the correct policy, we can create the transaction.
opid = self.nodes[2].z_sendmany(source, recipients, 1, 0, 'AllowRevealedSenders')
wait_and_assert_operationid_status(self.nodes[2], opid)
self.nodes[2].generate(1)
@ -181,7 +215,32 @@ class WalletZSendmanyTest(BitcoinTestFramework):
# Send some funds to a specific legacy taddr that we can spend from
recipients = []
recipients.append({"address":mytaddr, "amount":5})
opid = self.nodes[0].z_sendmany(n0ua0, recipients, 1, 0)
# If we attempt to spend with the default privacy policy, z_sendmany
# returns an error because it needs to create a transparent recipient in
# a transaction involving a Unified Address.
assert_raises_message(
JSONRPCException,
'AllowRevealedRecipients',
self.nodes[0].z_sendmany,
n0ua0, recipients, 1, 0)
# If we set any policy that does not include AllowRevealedRecipients,
# z_sendmany also returns an error.
for policy in [
'FullPrivacy',
'AllowRevealedAmounts',
'AllowRevealedSenders',
'AllowLinkingAccountAddresses',
]:
assert_raises_message(
JSONRPCException,
'AllowRevealedRecipients',
self.nodes[0].z_sendmany,
n0ua0, recipients, 1, 0, policy)
# By setting the correct policy, we can create the transaction.
opid = self.nodes[0].z_sendmany(n0ua0, recipients, 1, 0, 'AllowRevealedRecipients')
wait_and_assert_operationid_status(self.nodes[0], opid)
self.nodes[0].generate(1)
@ -204,10 +263,12 @@ class WalletZSendmanyTest(BitcoinTestFramework):
self.check_balance(0, 0, n0ua0, {'sapling': 2})
assert_equal(Decimal(self.nodes[2].z_getbalance(myzaddr)), zbalance)
# Send funds back from the legacy taddr to the UA
# Send funds back from the legacy taddr to the UA. This requires
# AllowRevealedSenders, but we can also use any weaker policy that
# includes it.
recipients = []
recipients.append({"address":n0ua0, "amount":4})
opid = self.nodes[2].z_sendmany(mytaddr, recipients, 1, 0)
opid = self.nodes[2].z_sendmany(mytaddr, recipients, 1, 0, 'AllowFullyTransparent')
wait_and_assert_operationid_status(self.nodes[2], opid)
self.nodes[2].generate(1)
@ -230,5 +291,99 @@ class WalletZSendmanyTest(BitcoinTestFramework):
self.check_balance(0, 0, n0ua0, {'sapling': 8})
assert_equal(Decimal(self.nodes[2].z_getbalance(myzaddr)), zbalance)
#
# Test that z_sendmany avoids UA linkability unless we allow it.
#
# Generate a new account with two new addresses.
n1account = self.nodes[1].z_getnewaccount()['account']
n1ua0 = self.nodes[1].z_getaddressforaccount(n1account)['unifiedaddress']
n1ua1 = self.nodes[1].z_getaddressforaccount(n1account)['unifiedaddress']
# Send funds to the transparent receivers of both addresses.
for ua in [n1ua0, n1ua1]:
taddr = self.nodes[1].z_listunifiedreceivers(ua)['transparent']
self.nodes[0].sendtoaddress(taddr, 2)
self.sync_all()
self.nodes[2].generate(1)
self.sync_all()
# The account should see all funds.
assert_equal(
self.nodes[1].z_getbalanceforaccount(n1account)['pools'],
{'transparent': {'valueZat': 4 * COIN}},
)
# The addresses should see only the transparent funds sent to them.
assert_equal(self.nodes[1].z_getbalance(n1ua0), 2)
assert_equal(self.nodes[1].z_getbalance(n1ua1), 2)
# If we try to send 3 ZEC from n1ua0, it will fail with too-few funds.
recipients = [{"address":n0ua0, "amount":3}]
linked_addrs_msg = 'Insufficient funds: have 2.00, need 3.00 (This transaction may require selecting transparent coins that were sent to multiple Unified Addresses, which is not enabled by default because it would create a public link between the transparent receivers of these addresses. THIS MAY AFFECT YOUR PRIVACY. Resubmit with the `privacyPolicy` parameter set to `AllowLinkingAccountAddresses` or weaker if you wish to allow this transaction to proceed anyway.)'
opid = self.nodes[1].z_sendmany(n1ua0, recipients, 1, 0)
wait_and_assert_operationid_status(self.nodes[1], opid, 'failed', linked_addrs_msg)
# If we try it again with any policy that is too strong, it also fails.
for policy in [
'FullPrivacy',
'AllowRevealedAmounts',
'AllowRevealedRecipients',
'AllowRevealedSenders',
'AllowFullyTransparent',
]:
opid = self.nodes[1].z_sendmany(n1ua0, recipients, 1, 0, policy)
wait_and_assert_operationid_status(self.nodes[1], opid, 'failed', linked_addrs_msg)
# Once we provide a sufficiently-weak policy, the transaction succeeds.
opid = self.nodes[1].z_sendmany(n1ua0, recipients, 1, 0, 'AllowLinkingAccountAddresses')
wait_and_assert_operationid_status(self.nodes[1], opid)
self.sync_all()
self.nodes[2].generate(1)
self.sync_all()
# The account should see the remaining funds, and they should have been
# sent to the Sapling change address (because NU5 is not active).
assert_equal(
self.nodes[1].z_getbalanceforaccount(n1account)['pools'],
{'sapling': {'valueZat': 1 * COIN}},
)
# The addresses should both show the same balance, as they both show the
# Sapling balance.
assert_equal(self.nodes[1].z_getbalance(n1ua0), 1)
assert_equal(self.nodes[1].z_getbalance(n1ua1), 1)
#
# Test NoPrivacy policy
#
# Send some legacy transparent funds to n1ua0, creating Sapling outputs.
recipients = [{"address":n1ua0, "amount":10}]
# This requires the AllowRevealedSenders policy...
opid = self.nodes[2].z_sendmany('ANY_TADDR', recipients, 1, 0)
wait_and_assert_operationid_status(self.nodes[2], opid, 'failed', revealed_senders_msg)
# ... which we can always override with the NoPrivacy policy.
opid = self.nodes[2].z_sendmany('ANY_TADDR', recipients, 1, 0, 'NoPrivacy')
wait_and_assert_operationid_status(self.nodes[2], opid)
self.sync_all()
self.nodes[2].generate(1)
self.sync_all()
# Send some funds from node 1's account to a transparent address.
recipients = [{"address":mytaddr, "amount":5}]
# This requires the AllowRevealedRecipients policy...
assert_raises_message(
JSONRPCException,
'AllowRevealedRecipients',
self.nodes[1].z_sendmany,
n1ua0, recipients, 1, 0)
# ... which we can always override with the NoPrivacy policy.
opid = self.nodes[1].z_sendmany(n1ua0, recipients, 1, 0, 'NoPrivacy')
wait_and_assert_operationid_status(self.nodes[1], opid)
if __name__ == '__main__':
WalletZSendmanyTest().main()

View File

@ -123,6 +123,16 @@ AsyncRPCOperation_sendmany::AsyncRPCOperation_sendmany(
}, recipient.address);
}
if (recipientPools_.count(OutputPool::Transparent) && !strategy_.AllowRevealedRecipients()) {
throw JSONRPCError(
RPC_INVALID_PARAMETER,
"This transaction would have transparent recipients, which is not "
"enabled by default because it will publicly reveal transaction "
"recipients and amounts. THIS MAY AFFECT YOUR PRIVACY. Resubmit "
"with the `privacyPolicy` parameter set to `AllowRevealedRecipients` "
"or weaker if you wish to allow this transaction to proceed anyway.");
}
// Log the context info i.e. the call parameters to z_sendmany
if (LogAcceptCategory("zrpcunsafe")) {
LogPrint("zrpcunsafe", "%s: z_sendmany initialized (params=%s)\n", getId(), contextInfo.write());
@ -247,6 +257,7 @@ uint256 AsyncRPCOperation_sendmany::main_impl() {
FormatMoney(changeAmount),
FormatMoney(dustThreshold)));
} else {
bool isFromUa = std::holds_alternative<libzcash::UnifiedAddress>(ztxoSelector_.GetPattern());
throw JSONRPCError(
RPC_WALLET_INSUFFICIENT_FUNDS,
strprintf(
@ -255,10 +266,27 @@ uint256 AsyncRPCOperation_sendmany::main_impl() {
+ (allowTransparentCoinbase ? "" :
"; note that coinbase outputs will not be selected if you specify "
"ANY_TADDR or if any transparent recipients are included.")
+ ((!isFromUa || strategy_.AllowLinkingAccountAddresses()) ? "" :
" (This transaction may require selecting transparent coins that were sent "
"to multiple Unified Addresses, which is not enabled by default because "
"it would create a public link between the transparent receivers of these "
"addresses. THIS MAY AFFECT YOUR PRIVACY. Resubmit with the `privacyPolicy` "
"parameter set to `AllowLinkingAccountAddresses` or weaker if you wish to "
"allow this transaction to proceed anyway.)")
);
}
}
if (!(spendable.utxos.empty() || strategy_.AllowRevealedSenders())) {
throw JSONRPCError(
RPC_INVALID_PARAMETER,
"This transaction requires selecting transparent coins, which is "
"not enabled by default because it will publicly reveal transaction "
"senders and amounts. THIS MAY AFFECT YOUR PRIVACY. Resubmit "
"with the `privacyPolicy` parameter set to `AllowRevealedSenders` "
"or weaker if you wish to allow this transaction to proceed anyway.");
}
spendable.LogInputs(getId());
CAmount t_inputs_total{0};

View File

@ -4493,9 +4493,22 @@ UniValue z_sendmany(const UniValue& params, bool fHelp)
" One of the following strings:\n"
" - \"FullPrivacy\": Only allow fully-shielded transactions (involving a single shielded pool).\n"
" - \"LegacyCompat\": If the transaction involves any Unified Addressess, this is equivalent to\n"
" \"FullPrivacy\". Otherwise, this is equivalent to \"AllowRevealedAmounts\".\n"
" \"FullPrivacy\". Otherwise, this is equivalent to \"AllowFullyTransparent\".\n"
" - \"AllowRevealedAmounts\": Allow funds to cross between shielded pools, revealing the amount\n"
" that crosses pools.\n"
" - \"AllowRevealedRecipients\": Allow transparent recipients. This also implies revealing\n"
" information described under \"AllowRevealedAmounts\".\n"
" - \"AllowRevealedSenders\": Allow transparent funds to be spent, revealing the sending\n"
" addresses and amounts. This implies revealing information described under \"AllowRevealedAmounts\".\n"
" - \"AllowFullyTransparent\": Allow transaction to both spend transparent funds and have\n"
" transparent recipients. This implies revealing information described under \"AllowRevealedSenders\"\n"
" and \"AllowRevealedRecipients\".\n"
" - \"AllowLinkingAccountAddresses\": Allow selecting transparent coins from the full account,\n"
" rather than just the funds sent to the transparent receiver in the provided Unified Address.\n"
" This implies revealing information described under \"AllowRevealedSenders\".\n"
" - \"NoPrivacy\": Allow the transaction to reveal any information necessary to create it.\n"
" This implies revealing information described under \"AllowFullyTransparent\" and\n"
" \"AllowLinkingAccountAddresses\".\n"
"\nResult:\n"
"\"operationid\" (string) An operationid to pass to z_getoperationstatus to get the result of the operation.\n"
"\nExamples:\n"
@ -4553,7 +4566,11 @@ UniValue z_sendmany(const UniValue& params, bool fHelp)
"Invalid from address: should be a taddr, zaddr, UA, or the string 'ANY_TADDR'.");
}
auto ztxoSelectorOpt = pwalletMain->ZTXOSelectorForAddress(decoded.value(), true, false);
auto ztxoSelectorOpt = pwalletMain->ZTXOSelectorForAddress(
decoded.value(),
true,
// LegacyCompat does not include AllowLinkingAccountAddresses.
maybeStrategy.has_value() ? maybeStrategy.value().AllowLinkingAccountAddresses() : false);
if (!ztxoSelectorOpt.has_value()) {
throw JSONRPCError(
RPC_INVALID_ADDRESS_OR_KEY,
@ -4669,7 +4686,7 @@ UniValue z_sendmany(const UniValue& params, bool fHelp)
// Default privacy policy is "LegacyCompat".
involvesUnifiedAddress ?
TransactionStrategy(PrivacyPolicy::FullPrivacy) :
TransactionStrategy(PrivacyPolicy::AllowRevealedAmounts)
TransactionStrategy(PrivacyPolicy::AllowFullyTransparent)
);
// Sanity check for transaction size

View File

@ -1249,7 +1249,7 @@ BOOST_AUTO_TEST_CASE(rpc_z_sendmany_internals)
auto selector = pwalletMain->ZTXOSelectorForAddress(zaddr1, true, false).value();
TransactionBuilder builder(consensusParams, nHeight + 1, std::nullopt, pwalletMain);
std::vector<SendManyRecipient> recipients = { SendManyRecipient(std::nullopt, taddr1, 100*COIN, "DEADBEEF") };
TransactionStrategy strategy;
TransactionStrategy strategy(PrivacyPolicy::AllowRevealedRecipients);
std::shared_ptr<AsyncRPCOperation> operation(new AsyncRPCOperation_sendmany(std::move(builder), selector, recipients, 1, strategy));
operation->main();
BOOST_CHECK(operation->isFailed());
@ -1363,7 +1363,7 @@ BOOST_AUTO_TEST_CASE(rpc_z_sendmany_taddr_to_sapling)
auto selector = pwalletMain->ZTXOSelectorForAddress(taddr, true, false).value();
std::vector<SendManyRecipient> recipients = { SendManyRecipient(std::nullopt, pa, 1*COIN, "ABCD") };
TransactionStrategy strategy;
TransactionStrategy strategy(PrivacyPolicy::AllowRevealedSenders);
std::shared_ptr<AsyncRPCOperation> operation(new AsyncRPCOperation_sendmany(std::move(builder), selector, recipients, 0, strategy));
std::shared_ptr<AsyncRPCOperation_sendmany> ptr = std::dynamic_pointer_cast<AsyncRPCOperation_sendmany> (operation);
@ -1372,7 +1372,9 @@ BOOST_AUTO_TEST_CASE(rpc_z_sendmany_taddr_to_sapling)
// Generate the Sapling shielding transaction
operation->main();
BOOST_CHECK(operation->isSuccess());
if (!operation->isSuccess()) {
BOOST_FAIL(operation->getErrorMessage());
}
// Get the transaction
auto result = operation->getResult();

View File

@ -7096,6 +7096,16 @@ std::optional<TransactionStrategy> TransactionStrategy::FromString(std::string p
strategy.privacy = PrivacyPolicy::FullPrivacy;
} else if (privacyPolicy == "AllowRevealedAmounts") {
strategy.privacy = PrivacyPolicy::AllowRevealedAmounts;
} else if (privacyPolicy == "AllowRevealedRecipients") {
strategy.privacy = PrivacyPolicy::AllowRevealedRecipients;
} else if (privacyPolicy == "AllowRevealedSenders") {
strategy.privacy = PrivacyPolicy::AllowRevealedSenders;
} else if (privacyPolicy == "AllowFullyTransparent") {
strategy.privacy = PrivacyPolicy::AllowFullyTransparent;
} else if (privacyPolicy == "AllowLinkingAccountAddresses") {
strategy.privacy = PrivacyPolicy::AllowLinkingAccountAddresses;
} else if (privacyPolicy == "NoPrivacy") {
strategy.privacy = PrivacyPolicy::NoPrivacy;
} else {
// Unknown privacy policy.
return std::nullopt;
@ -7109,6 +7119,62 @@ bool TransactionStrategy::AllowRevealedAmounts() {
case PrivacyPolicy::FullPrivacy:
return false;
case PrivacyPolicy::AllowRevealedAmounts:
case PrivacyPolicy::AllowRevealedRecipients:
case PrivacyPolicy::AllowRevealedSenders:
case PrivacyPolicy::AllowFullyTransparent:
case PrivacyPolicy::AllowLinkingAccountAddresses:
case PrivacyPolicy::NoPrivacy:
return true;
default:
// Fail closed.
return false;
}
}
bool TransactionStrategy::AllowRevealedRecipients() {
switch (privacy) {
case PrivacyPolicy::FullPrivacy:
case PrivacyPolicy::AllowRevealedAmounts:
case PrivacyPolicy::AllowRevealedSenders:
case PrivacyPolicy::AllowLinkingAccountAddresses:
return false;
case PrivacyPolicy::AllowRevealedRecipients:
case PrivacyPolicy::AllowFullyTransparent:
case PrivacyPolicy::NoPrivacy:
return true;
default:
// Fail closed.
return false;
}
}
bool TransactionStrategy::AllowRevealedSenders() {
switch (privacy) {
case PrivacyPolicy::FullPrivacy:
case PrivacyPolicy::AllowRevealedAmounts:
case PrivacyPolicy::AllowRevealedRecipients:
return false;
case PrivacyPolicy::AllowRevealedSenders:
case PrivacyPolicy::AllowFullyTransparent:
case PrivacyPolicy::AllowLinkingAccountAddresses:
case PrivacyPolicy::NoPrivacy:
return true;
default:
// Fail closed.
return false;
}
}
bool TransactionStrategy::AllowLinkingAccountAddresses() {
switch (privacy) {
case PrivacyPolicy::FullPrivacy:
case PrivacyPolicy::AllowRevealedAmounts:
case PrivacyPolicy::AllowRevealedRecipients:
case PrivacyPolicy::AllowRevealedSenders:
case PrivacyPolicy::AllowFullyTransparent:
return false;
case PrivacyPolicy::AllowLinkingAccountAddresses:
case PrivacyPolicy::NoPrivacy:
return true;
default:
// Fail closed.

View File

@ -721,6 +721,11 @@ public:
enum class PrivacyPolicy {
FullPrivacy,
AllowRevealedAmounts,
AllowRevealedRecipients,
AllowRevealedSenders,
AllowFullyTransparent,
AllowLinkingAccountAddresses,
NoPrivacy,
};
class TransactionStrategy {
@ -734,6 +739,9 @@ public:
static std::optional<TransactionStrategy> FromString(std::string privacyPolicy);
bool AllowRevealedAmounts();
bool AllowRevealedRecipients();
bool AllowRevealedSenders();
bool AllowLinkingAccountAddresses();
};
/**