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:
parent
322aee238a
commit
9554ed2dc4
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Reference in New Issue