diff --git a/qa/rpc-tests/wallet.py b/qa/rpc-tests/wallet.py index 158a77c88..4578b1025 100755 --- a/qa/rpc-tests/wallet.py +++ b/qa/rpc-tests/wallet.py @@ -463,6 +463,62 @@ class WalletTest (BitcoinTestFramework): assert_equal("not an integer" in errorString, True); + myzaddr = self.nodes[0].z_getnewaddress() + recipients = [ {"address": myzaddr, "amount": Decimal('0.0') } ] + errorString = '' + + # Make sure that amount=0 transactions can use the default fee + # without triggering "absurd fee" errors + try: + myopid = self.nodes[0].z_sendmany(myzaddr, recipients) + assert(myopid) + except JSONRPCException,e: + errorString = e.error['message'] + print errorString + assert(False) + + # This fee is larger than the default fee and since amount=0 + # it should trigger error + fee = Decimal('0.1') + recipients = [ {"address": myzaddr, "amount": Decimal('0.0') } ] + minconf = 1 + errorString = '' + + try: + myopid = self.nodes[0].z_sendmany(myzaddr, recipients, minconf, fee) + except JSONRPCException,e: + errorString = e.error['message'] + assert('Small transaction amount' in errorString) + + #### This fee is less than default and greater than amount, but still valid + fee = Decimal('0.0000001') + recipients = [ {"address": myzaddr, "amount": Decimal('0.00000001') } ] + minconf = 1 + errorString = '' + + try: + myopid = self.nodes[0].z_sendmany(myzaddr, recipients, minconf, fee) + assert(myopid) + except JSONRPCException,e: + errorString = e.error['message'] + print errorString + assert(False) + + ### Make sure amount=0, fee=0 transaction are valid to add to mempool + # though miners decide whether to add to a block + fee = Decimal('0.0') + minconf = 1 + recipients = [ {"address": myzaddr, "amount": Decimal('0.0') } ] + errorString = '' + + try: + myopid = self.nodes[0].z_sendmany(myzaddr, recipients, minconf, fee) + assert(myopid) + except JSONRPCException,e: + errorString = e.error['message'] + print errorString + assert(False) + if __name__ == '__main__': WalletTest ().main () diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 5476ce247..cef9f569e 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -3698,7 +3698,9 @@ UniValue z_sendmany(const UniValue& params, bool fHelp) } // Fee in Zatoshis, not currency format) - CAmount nFee = ASYNC_RPC_OPERATION_DEFAULT_MINERS_FEE; + CAmount nFee = ASYNC_RPC_OPERATION_DEFAULT_MINERS_FEE; + CAmount nDefaultFee = nFee; + if (params.size() > 3) { if (params[3].get_real() == 0.0) { nFee = 0; @@ -3707,9 +3709,18 @@ UniValue z_sendmany(const UniValue& params, bool fHelp) } // 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))); - } + // This allows amount=0 (and all amount < nDefaultFee) transactions to use the default network fee + // or anything less than nDefaultFee instead of being forced to use a custom fee and leak metadata + if (nTotalOut < nDefaultFee) { + if (nFee > nDefaultFee) { + throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Small transaction amount %s has fee %s that is greater than the default fee %s", FormatMoney(nTotalOut), FormatMoney(nFee), FormatMoney(nDefaultFee))); + } + } else { + // 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))); + } + } } // Use input parameters as the optional context info to be returned by z_getoperationstatus and z_getoperationresult.