Auto merge of #1907 - bitcartel:1903_z_sendmany_fee_parameter, r=ebfull

Closes #1903. Add fee parameter to z_sendmany.
This commit is contained in:
zkbot
2016-12-07 16:58:26 +00:00
7 changed files with 81 additions and 13 deletions

View File

@@ -103,6 +103,7 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "z_gettotalbalance", 0},
{ "z_sendmany", 1},
{ "z_sendmany", 2},
{ "z_sendmany", 3},
{ "z_getoperationstatus", 0},
{ "z_getoperationresult", 0},
{ "z_importkey", 1 }

View File

@@ -820,7 +820,7 @@ BOOST_AUTO_TEST_CASE(rpc_z_sendmany_parameters)
BOOST_CHECK_THROW(CallRPC("z_sendmany"), runtime_error);
BOOST_CHECK_THROW(CallRPC("z_sendmany toofewargs"), runtime_error);
BOOST_CHECK_THROW(CallRPC("z_sendmany too many args here"), runtime_error);
BOOST_CHECK_THROW(CallRPC("z_sendmany just too many args here"), runtime_error);
// bad from address
BOOST_CHECK_THROW(CallRPC("z_sendmany "
@@ -841,6 +841,27 @@ BOOST_AUTO_TEST_CASE(rpc_z_sendmany_parameters)
" {\"address\":\"tmQP9L3s31cLsghVYf2Jb5MhKj1jRBPoeQn\", \"amount\":12.0} ]"
), runtime_error);
// invalid fee amount, cannot be negative
BOOST_CHECK_THROW(CallRPC("z_sendmany "
"tmRr6yJonqGK23UVhrKuyvTpF8qxQQjKigJ "
"[{\"address\":\"tmQP9L3s31cLsghVYf2Jb5MhKj1jRBPoeQn\", \"amount\":50.0}] "
"1 -0.0001"
), runtime_error);
// invalid fee amount, bigger than MAX_MONEY
BOOST_CHECK_THROW(CallRPC("z_sendmany "
"tmRr6yJonqGK23UVhrKuyvTpF8qxQQjKigJ "
"[{\"address\":\"tmQP9L3s31cLsghVYf2Jb5MhKj1jRBPoeQn\", \"amount\":50.0}] "
"1 21000001"
), runtime_error);
// fee amount is bigger than sum of outputs
BOOST_CHECK_THROW(CallRPC("z_sendmany "
"tmRr6yJonqGK23UVhrKuyvTpF8qxQQjKigJ "
"[{\"address\":\"tmQP9L3s31cLsghVYf2Jb5MhKj1jRBPoeQn\", \"amount\":50.0}] "
"1 50.00000001"
), runtime_error);
// memo bigger than allowed length of ZC_MEMO_SIZE
std::vector<char> v (2 * (ZC_MEMO_SIZE+1)); // x2 for hexadecimal string format
std::fill(v.begin(),v.end(), 'A');

View File

@@ -50,9 +50,12 @@ AsyncRPCOperation_sendmany::AsyncRPCOperation_sendmany(
std::string fromAddress,
std::vector<SendManyRecipient> tOutputs,
std::vector<SendManyRecipient> zOutputs,
int minDepth) :
fromaddress_(fromAddress), t_outputs_(tOutputs), z_outputs_(zOutputs), mindepth_(minDepth)
int minDepth,
CAmount fee) :
fromaddress_(fromAddress), t_outputs_(tOutputs), z_outputs_(zOutputs), mindepth_(minDepth), fee_(fee)
{
assert(fee_ > 0);
if (minDepth < 0) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Minconf cannot be negative");
}
@@ -147,8 +150,8 @@ bool AsyncRPCOperation_sendmany::main_impl() {
bool isSingleZaddrOutput = (t_outputs_.size()==0 && z_outputs_.size()==1);
bool isMultipleZaddrOutput = (t_outputs_.size()==0 && z_outputs_.size()>=1);
bool isPureTaddrOnlyTx = (isfromtaddr_ && z_outputs_.size() == 0);
CAmount minersFee = ASYNC_RPC_OPERATION_DEFAULT_MINERS_FEE;
CAmount minersFee = fee_;
// When spending coinbase utxos, you can only specify a single zaddr as the change must go somewhere
// and if there are multiple zaddrs, we don't know where to send it.
if (isfromtaddr_) {

View File

@@ -16,7 +16,7 @@
#include <tuple>
// TODO: Compute fee based on a heuristic, e.g. (num tx output * dust threshold) + joinsplit bytes * ?
// Default transaction fee if caller does not specify one.
#define ASYNC_RPC_OPERATION_DEFAULT_MINERS_FEE 10000
using namespace libzcash;
@@ -43,7 +43,7 @@ struct AsyncJoinSplitInfo
class AsyncRPCOperation_sendmany : public AsyncRPCOperation {
public:
AsyncRPCOperation_sendmany(std::string fromAddress, std::vector<SendManyRecipient> tOutputs, std::vector<SendManyRecipient> zOutputs, int minDepth);
AsyncRPCOperation_sendmany(std::string fromAddress, std::vector<SendManyRecipient> tOutputs, std::vector<SendManyRecipient> zOutputs, int minDepth, CAmount fee = ASYNC_RPC_OPERATION_DEFAULT_MINERS_FEE);
virtual ~AsyncRPCOperation_sendmany();
// We don't want to be copied or moved around
@@ -59,6 +59,7 @@ public:
private:
friend class TEST_FRIEND_AsyncRPCOperation_sendmany; // class for unit testing
CAmount fee_;
int mindepth_;
std::string fromaddress_;
bool isfromtaddr_;

View File

@@ -3182,9 +3182,9 @@ Value z_sendmany(const Array& params, bool fHelp)
if (!EnsureWalletIsAvailable(fHelp))
return Value::null;
if (fHelp || params.size() < 2 || params.size() > 3)
if (fHelp || params.size() < 2 || params.size() > 4)
throw runtime_error(
"z_sendmany \"fromaddress\" [{\"address\":... ,\"amount\":...},...] ( minconf )\n"
"z_sendmany \"fromaddress\" [{\"address\":... ,\"amount\":...},...] ( minconf ) ( fee )\n"
"\nSend multiple times. Amounts are double-precision floating point numbers."
"\nChange from a taddr flows to a new taddr address, while change from zaddr returns to itself."
"\nWhen sending coinbase UTXOs to a zaddr, change is not allowed. The entire value of the UTXO(s) must be consumed."
@@ -3199,6 +3199,8 @@ Value z_sendmany(const Array& 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(ASYNC_RPC_OPERATION_DEFAULT_MINERS_FEE)) + ") The fee amount to attach to this transaction.\n"
"\nResult:\n"
"\"operationid\" (string) An operationid to pass to z_getoperationstatus to get the result of the operation.\n"
);
@@ -3239,6 +3241,7 @@ Value z_sendmany(const Array& params, bool fHelp)
// Recipients
std::vector<SendManyRecipient> taddrRecipients;
std::vector<SendManyRecipient> zaddrRecipients;
CAmount nTotalOut = 0;
BOOST_FOREACH(Value& output, outputs)
{
@@ -3294,6 +3297,8 @@ Value z_sendmany(const Array& params, bool fHelp)
} else {
taddrRecipients.push_back( SendManyRecipient(address, nAmount, memo) );
}
nTotalOut += nAmount;
}
// Check the number of zaddr outputs does not exceed the limit.
@@ -3329,9 +3334,19 @@ Value z_sendmany(const Array& params, bool fHelp)
throw JSONRPCError(RPC_INVALID_PARAMETER, "Minimum number of confirmations cannot be less than 0");
}
// Fee in Zatoshis, not currency format)
CAmount nFee = ASYNC_RPC_OPERATION_DEFAULT_MINERS_FEE;
if (params.size() > 3) {
nFee = AmountFromValue( params[3] );
// Check that the user specified fee is sane.
if (nFee > nTotalOut) {
throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Fee %s is greater than the sum of outputs %s", FormatMoney(nFee), FormatMoney(nTotalOut)));
}
}
// Create operation and add to global queue
std::shared_ptr<AsyncRPCQueue> q = getAsyncRPCQueue();
std::shared_ptr<AsyncRPCOperation> operation( new AsyncRPCOperation_sendmany(fromaddress, taddrRecipients, zaddrRecipients, nMinDepth) );
std::shared_ptr<AsyncRPCOperation> operation( new AsyncRPCOperation_sendmany(fromaddress, taddrRecipients, zaddrRecipients, nMinDepth, nFee) );
q->addOperation(operation);
AsyncRPCOperationId operationId = operation->getId();
return operationId;