Implement z_sendmany RPC call.

Simple implementation does not try to optimize coin or note selection.
Caller can send from a taddr or zaddr to multiple recipients.
Currently only one of the recipients can be a zaddr.
This commit is contained in:
Simon
2016-08-20 22:54:40 -07:00
parent 4eb1a96f9a
commit dafb81614b
3 changed files with 661 additions and 78 deletions

View File

@@ -2870,7 +2870,7 @@ Value z_getoperationstatus(const Array& params, bool fHelp)
return status;
}
// If there is any change, it will flow back to the source taddr or zaddr.
Value z_sendmany(const Array& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
@@ -2879,7 +2879,7 @@ Value z_sendmany(const Array& params, bool fHelp)
if (fHelp || params.size() < 2 || params.size() > 3)
throw runtime_error(
"z_sendmany \"fromaddress\" [{\"address\":... ,\"amount\":...},...] ( minconf )\n"
"\n*** THIS COMMAND HAS NOT BEEN IMPLEMENTED YET ***"
"\n*** This alpha release supports multiple recipients, but only one of them can be a zaddr ***"
"\nSend multiple times. Amounts are double-precision floating point numbers."
+ HelpRequiringPassphrase() + "\n"
"\nArguments:\n"
@@ -2897,7 +2897,6 @@ Value z_sendmany(const Array& params, bool fHelp)
LOCK2(cs_main, pwalletMain->cs_wallet);
// Check that the from address is valid.
auto fromaddress = params[0].get_str();
bool fromTaddr = false;
@@ -2914,14 +2913,13 @@ Value z_sendmany(const Array& params, bool fHelp)
}
}
// Check that we have the spending key?
// Check that we have the spending key
if (!fromTaddr) {
if (!pwalletMain->HaveSpendingKey(zaddr)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "From address does not belong to this node, zaddr spending key not found.");
}
}
Array outputs = params[1].get_array();
if (outputs.size()==0)
@@ -2931,7 +2929,8 @@ Value z_sendmany(const Array& params, bool fHelp)
set<std::string> setAddress;
// Recipients
std::vector<SendManyRecipient> recipients;
std::vector<SendManyRecipient> taddrRecipients;
std::vector<SendManyRecipient> zaddrRecipients;
BOOST_FOREACH(Value& output, outputs)
{
@@ -2942,7 +2941,6 @@ Value z_sendmany(const Array& params, bool fHelp)
RPCTypeCheck(o, boost::assign::map_list_of("address", str_type)("amount", real_type));
// sanity check, report error if unknown key-value pairs
// for (auto& p : o) {
for (const Pair& p : o) {
std::string s = p.name_;
if (s != "address" && s != "amount" && s!="memo")
@@ -2975,46 +2973,37 @@ Value z_sendmany(const Array& params, bool fHelp)
} else if (!IsHex(memo)) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected memo data in hexadecimal format.");
}
std::vector<unsigned char> vMemo = ParseHex(memo);
if (vMemo.size() > ZC_MEMO_SIZE) {
throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid parameter, size of memo is larger than maximum allowed %d", ZC_MEMO_SIZE ));
}
}
//int nOutput = find_value(o, "amount").get_real(); // int();
Value av = find_value(o, "amount");
CAmount nAmount = AmountFromValue( av );
if (nAmount < 0)
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, amount must be positive");
recipients.push_back( SendManyRecipient(address, nAmount, memo) );
if (isZaddr) {
zaddrRecipients.push_back( SendManyRecipient(address, nAmount, memo) );
} else {
taddrRecipients.push_back( SendManyRecipient(address, nAmount, memo) );
}
}
// Limitation of z9 alpha, only one zaddr allowed in output.
if (zaddrRecipients.size() > 1)
throw JSONRPCError(RPC_INVALID_PARAMETER, "Too many zaddrs as recipients. Alpha preview only allows one zaddr as a recipient");
// Minimum confirmations
int nMinDepth = 1;
if (params.size() > 2)
nMinDepth = params[2].get_int();
// std::vector<string>
// GetPaymentAddresses(addresses);
// for (auto addr : addresses ) {
// ret.push_back(CZCPaymentAddress(addr).ToString());
// }
// Create operation and add to global queue
std::shared_ptr<AsyncRPCQueue> q = getAsyncRPCQueue();
std::shared_ptr<AsyncRPCOperation> operation( new AsyncRPCOperation_sendmany(fromaddress, recipients, nMinDepth) );
// operation->
//std::shared_ptr<AsyncRPCOperation> operation = make_shared<AsyncRPCOperation>(AsyncRPCOperation_sendmany());
std::shared_ptr<AsyncRPCOperation> operation( new AsyncRPCOperation_sendmany(fromaddress, taddrRecipients, zaddrRecipients, nMinDepth) );
q->addOperation(operation);
AsyncRPCOperationId operationId = operation->getId();
return operationId;
// return Value::null;
// Array ret;
// std::set<libzcash::PaymentAddress> addresses;
// pwalletMain->GetPaymentAddresses(addresses);
// for (auto addr : addresses ) {
// ret.push_back(CZCPaymentAddress(addr).ToString());
// }
// return ret;
}