Additional z_sendmany test cases

Also improve error messages.
This commit is contained in:
Greg Pfeil 2023-03-20 11:24:50 -06:00
parent 62ae44a131
commit 1f72b42b81
No known key found for this signature in database
GPG Key ID: 1193ACD196ED61F2
4 changed files with 59 additions and 4 deletions

View File

@ -339,6 +339,10 @@ class WalletZSendmanyTest(BitcoinTestFramework):
opid = self.nodes[1].z_sendmany(n1ua0, recipients, 1, 0, policy)
wait_and_assert_operationid_status(self.nodes[1], opid, 'failed', msg)
# If we try to send just a bit less than we have, it will fail, complaining about dust
opid = self.nodes[1].z_sendmany(n1ua0, [{"address":n0ua0, "amount":3.9999999}], 1, 0, 'AllowLinkingAccountAddresses')
wait_and_assert_operationid_status(self.nodes[1], opid, 'failed', 'Insufficient funds: have 4.00, need 0.00000044 more to avoid creating invalid change output 0.0000001 (dust threshold is 0.00000054).')
# 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)
@ -359,6 +363,20 @@ class WalletZSendmanyTest(BitcoinTestFramework):
assert_equal(self.nodes[1].z_getbalance(n1ua0), 1)
assert_equal(self.nodes[1].z_getbalance(n1ua1), 1)
#
# Test Orchard-only UA before NU5
#
n0orchard_only = self.nodes[0].z_getaddressforaccount(n0account0, ["orchard"])['address']
recipients = [{"address":n0orchard_only, "amount":1}]
for (policy, msg) in [
('FullPrivacy', 'Could not send to a shielded receiver of a unified address without spending funds from a different pool, which would reveal transaction amounts. THIS MAY AFFECT YOUR PRIVACY. Resubmit with the `privacyPolicy` parameter set to `AllowRevealedAmounts` or weaker if you wish to allow this transaction to proceed anyway.'),
('AllowRevealedAmounts', 'This transaction would send to a transparent receiver of a unified address, 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.'),
('AllowRevealedRecipients', 'Could not send to an Orchard-only receiver, despite a lax privacy policy. Either there are insufficent non-Sprout funds, or NU5 has not been activated yet.'),
]:
opid = self.nodes[1].z_sendmany(n1ua0, recipients, 1, 0, policy)
wait_and_assert_operationid_status(self.nodes[1], opid, 'failed', msg)
#
# Test NoPrivacy policy
#
@ -392,6 +410,19 @@ class WalletZSendmanyTest(BitcoinTestFramework):
self.nodes[1].generate(10)
self.sync_all()
#
# Test Orchard-only UA with insufficient non-Sprout funds
#
recipients = [{"address":n0orchard_only, "amount":100}]
for (policy, msg) in [
('FullPrivacy', 'Could not send to a shielded receiver of a unified address without spending funds from a different pool, which would reveal transaction amounts. THIS MAY AFFECT YOUR PRIVACY. Resubmit with the `privacyPolicy` parameter set to `AllowRevealedAmounts` or weaker if you wish to allow this transaction to proceed anyway.'),
('AllowRevealedAmounts', 'This transaction would send to a transparent receiver of a unified address, 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.'),
('AllowRevealedRecipients', 'Could not send to an Orchard-only receiver, despite a lax privacy policy. Either there are insufficent non-Sprout funds, or NU5 has not been activated yet.'),
]:
opid = self.nodes[1].z_sendmany(n1ua0, recipients, 1, 0, policy)
wait_and_assert_operationid_status(self.nodes[1], opid, 'failed', msg)
#
# Test AllowRevealedAmounts policy
#

View File

@ -139,14 +139,24 @@ void ThrowInputSelectionError(
FormatMoney(err.available - err.required)));
},
[](const ExcessOrchardActionsError& err) {
std::string side;
switch (err.side) {
case ActionSide::Input:
side = "inputs";
case ActionSide::Output:
side = "outputs";
case ActionSide::Both:
side = "actions";
};
throw JSONRPCError(
RPC_INVALID_PARAMETER,
strprintf(
"Attempting to spend %u Orchard notes would exceed the current limit "
"Including %u Orchard %s would exceed the current limit "
"of %u notes, which exists to prevent memory exhaustion. Restart with "
"`-orchardactionlimit=N` where N >= %u to allow the wallet to attempt "
"to construct this transaction.",
err.orchardNotes,
side,
err.maxNotes,
err.orchardNotes));
}

View File

@ -307,7 +307,10 @@ InputSelectionResult WalletTxBuilder::ResolveInputsAndPayments(
auto resolved = Payments(resolvedPayments);
if (orchardOutputs > this->maxOrchardActions) {
return ExcessOrchardActionsError(orchardOutputs, this->maxOrchardActions);
return ExcessOrchardActionsError(
ActionSide::Output,
orchardOutputs,
this->maxOrchardActions);
}
// Set the dust threshold so that we can select enough inputs to avoid
@ -343,7 +346,10 @@ InputSelectionResult WalletTxBuilder::ResolveInputsAndPayments(
}
if (spendableMut.orchardNoteMetadata.size() > this->maxOrchardActions) {
return ExcessOrchardActionsError(spendableMut.orchardNoteMetadata.size(), this->maxOrchardActions);
return ExcessOrchardActionsError(
ActionSide::Input,
spendableMut.orchardNoteMetadata.size(),
this->maxOrchardActions);
}
return InputSelection(resolved, anchorHeight);

View File

@ -260,12 +260,20 @@ public:
available(available), required(required) { }
};
enum ActionSide {
Input,
Output,
Both,
};
class ExcessOrchardActionsError {
public:
ActionSide side;
uint32_t orchardNotes;
uint32_t maxNotes;
ExcessOrchardActionsError(uint32_t orchardNotes, uint32_t maxNotes): orchardNotes(orchardNotes), maxNotes(maxNotes) { }
ExcessOrchardActionsError(ActionSide side, uint32_t orchardNotes, uint32_t maxNotes):
side(side), orchardNotes(orchardNotes), maxNotes(maxNotes) { }
};
typedef std::variant<