Require an explicit flag to allow cross-pool transfers in z_sendmany.

This adds an `allowRevealedAmounts` argument to z_sendmany. This
flag must be present to allow an amount-revealing cross-pool transfer
to be constructed.
This commit is contained in:
Kris Nuttycombe 2022-01-11 08:55:48 -07:00
parent 322aee238a
commit 9554ed2dc4
4 changed files with 33 additions and 13 deletions

View File

@ -67,7 +67,7 @@ class WalletListNotes(BitcoinTestFramework):
change_amount_2 = receive_amount_1 - receive_amount_2 - DEFAULT_FEE
assert_equal('sapling', self.nodes[0].z_validateaddress(saplingzaddr)['type'])
recipients = [{"address": saplingzaddr, "amount":receive_amount_2}]
myopid = self.nodes[0].z_sendmany(sproutzaddr, recipients)
myopid = self.nodes[0].z_sendmany(sproutzaddr, recipients, 1, DEFAULT_FEE, True)
txid_2 = wait_and_assert_operationid_status(self.nodes[0], myopid)
self.sync_all()
@ -104,7 +104,7 @@ class WalletListNotes(BitcoinTestFramework):
receive_amount_3 = Decimal('2.0')
change_amount_3 = change_amount_2 - receive_amount_3 - DEFAULT_FEE
recipients = [{"address": saplingzaddr2, "amount":receive_amount_3}]
myopid = self.nodes[0].z_sendmany(sproutzaddr, recipients)
myopid = self.nodes[0].z_sendmany(sproutzaddr, recipients, 1, DEFAULT_FEE, True)
txid_3 = wait_and_assert_operationid_status(self.nodes[0], myopid)
self.sync_all()
unspent_tx = self.nodes[0].z_listunspent(0)

View File

@ -49,8 +49,11 @@ AsyncRPCOperation_sendmany::AsyncRPCOperation_sendmany(
std::vector<SendManyRecipient> recipients,
int minDepth,
CAmount fee,
bool allowRevealedAmounts,
UniValue contextInfo) :
builder_(builder), paymentSource_(paymentSource), recipients_(recipients), mindepth_(minDepth), fee_(fee), contextinfo_(contextInfo)
builder_(builder), paymentSource_(paymentSource), recipients_(recipients),
mindepth_(minDepth), fee_(fee), allowRevealedAmounts_(allowRevealedAmounts),
contextinfo_(contextInfo)
{
assert(fee_ >= 0);
assert(mindepth_ >= 0);
@ -76,10 +79,10 @@ AsyncRPCOperation_sendmany::AsyncRPCOperation_sendmany(
isfromtaddr_ = true;
},
[&](const libzcash::SproutPaymentAddress& addr) {
isfromzaddr_ = true;
isfromsprout_ = true;
},
[&](const libzcash::SaplingPaymentAddress& addr) {
isfromzaddr_ = true;
isfromsapling_ = true;
},
[&](const libzcash::UnifiedAddress& addr) {
throw JSONRPCError(
@ -90,7 +93,7 @@ AsyncRPCOperation_sendmany::AsyncRPCOperation_sendmany(
}
}, paymentSource);
if (isfromzaddr_ && minDepth==0) {
if ((isfromsprout_ || isfromsapling_) && minDepth==0) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Minconf cannot be zero when sending from zaddr");
}
@ -193,7 +196,8 @@ bool IsFromAnyTaddr(const PaymentSource& paymentSource) {
// 2. #1360 Note selection is not optimal
// 3. #1277 Spendable notes are not locked, so an operation running in parallel could also try to use them
uint256 AsyncRPCOperation_sendmany::main_impl() {
// TODO UA: these flags will become meaningless.
// TODO UA: this check will become meaningless.
bool isfromzaddr_ = isfromsprout_ || isfromsapling_;
assert(isfromtaddr_ != isfromzaddr_);
TxValues txValues;
@ -218,6 +222,14 @@ uint256 AsyncRPCOperation_sendmany::main_impl() {
[&](const libzcash::SaplingPaymentAddress& addr) {
txValues.z_outputs_total += recipient.amount;
shieldedRecipients += 1;
if (isfromsprout_ && !allowRevealedAmounts_) {
throw JSONRPCError(
RPC_INVALID_PARAMETER,
"Sending from Sprout to Sapling is not enabled by default because it will "
"publicly reveal the transaction amount. THIS MAY AFFECT YOUR PRIVACY. "
"Resubmit with the `allowRevealedAmounts` parameter set to `true` if "
"you wish to allow this transaction to proceed anyway.");
}
},
[&](const libzcash::UnifiedAddress& ua) {
// unreachable; currently disallowed by checks at construction

View File

@ -92,6 +92,7 @@ public:
std::vector<SendManyRecipient> recipients,
int minDepth,
CAmount fee = DEFAULT_FEE,
bool allowRevealedAmounts = false,
UniValue contextInfo = NullUniValue);
virtual ~AsyncRPCOperation_sendmany();
@ -118,7 +119,9 @@ private:
UniValue contextinfo_; // optional data to include in return value from getStatus()
bool isfromtaddr_{false};
bool isfromzaddr_{false};
bool isfromsprout_{false};
bool isfromsapling_{false};
bool allowRevealedAmounts_{false};
SpendableInputs FindSpendableInputs(bool fAcceptCoinbase);

View File

@ -3760,9 +3760,9 @@ UniValue z_sendmany(const UniValue& params, bool fHelp)
if (!EnsureWalletIsAvailable(fHelp))
return NullUniValue;
if (fHelp || params.size() < 2 || params.size() > 4)
if (fHelp || params.size() < 2 || params.size() > 5)
throw runtime_error(
"z_sendmany \"fromaddress\" [{\"address\":... ,\"amount\":...},...] ( minconf ) ( fee )\n"
"z_sendmany \"fromaddress\" [{\"address\":... ,\"amount\":...},...] ( minconf ) ( fee ) ( allowRevealedAmounts )\n"
"\nSend multiple times. Amounts are decimal numbers with at most 8 digits of precision."
"\nChange generated from one or more transparent addresses flows to a new transparent"
"\naddress, while change generated from a shielded address returns to itself."
@ -3782,8 +3782,8 @@ UniValue z_sendmany(const UniValue& params, bool fHelp)
" \"memo\":memo (string, optional) If the address is a zaddr, raw data represented in hexadecimal string format\n"
" }, ... ]\n"
"3. minconf (numeric, optional, default=1) Only use funds confirmed at least this many times.\n"
"4. fee (numeric, optional, default="
+ strprintf("%s", FormatMoney(DEFAULT_FEE)) + ") The fee amount to attach to this transaction.\n"
"4. fee (numeric, optional, default=" + strprintf("%s", FormatMoney(DEFAULT_FEE)) + ") The fee amount to attach to this transaction.\n"
"5. allowRevealedAmounts (bool, optional, default=false) Permit cross-shielded-pool transfers, which will publicly reveal the amount(s) crossing pool boundaries.\n"
"\nResult:\n"
"\"operationid\" (string) An operationid to pass to z_getoperationstatus to get the result of the operation.\n"
"\nExamples:\n"
@ -3946,6 +3946,11 @@ UniValue z_sendmany(const UniValue& params, bool fHelp)
}
}
bool allowRevealedAmounts{false};
if (params.size() > 4) {
allowRevealedAmounts = params[4].get_bool();
}
// Use input parameters as the optional context info to be returned by z_getoperationstatus and z_getoperationresult.
UniValue o(UniValue::VOBJ);
o.pushKV("fromaddress", params[0]);
@ -3960,7 +3965,7 @@ UniValue z_sendmany(const UniValue& params, bool fHelp)
// Create operation and add to global queue
std::shared_ptr<AsyncRPCQueue> q = getAsyncRPCQueue();
std::shared_ptr<AsyncRPCOperation> operation(
new AsyncRPCOperation_sendmany(builder, paymentSource, recipients, nMinDepth, nFee, contextInfo)
new AsyncRPCOperation_sendmany(builder, paymentSource, recipients, nMinDepth, nFee, allowRevealedAmounts, contextInfo)
);
q->addOperation(operation);
AsyncRPCOperationId operationId = operation->getId();