diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index f786fea36..8cf4d6502 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -317,6 +317,7 @@ UniValue createrawtransaction(const JSONRPCRequest& request) "3. locktime (numeric, optional, default=0) Raw locktime. Non-0 value also locktime-activates inputs\n" "4. replaceable (boolean, optional, default=false) Marks this transaction as BIP125 replaceable.\n" " Allows this transaction to be replaced by a transaction with higher fees. If provided, it is an error if explicit sequence numbers are incompatible.\n" + "5. tx-comment (string, optional) Transaction tx-comment (default = \"\").\n" "\nResult:\n" "\"transaction\" (string) hex string of the transaction\n" @@ -345,7 +346,10 @@ UniValue createrawtransaction(const JSONRPCRequest& request) bool rbfOptIn = request.params.size() > 3 ? request.params[3].isTrue() : false; - rawTx.strTxComment = request.params.size() > 4 ? request.params[4].get_string() : ""; + rawTx.strTxComment = ""; + if (request.params.size() > 4 && !request.params[4].isNull()) { + rawTx.strTxComment = request.params[4].get_str(); + } for (unsigned int idx = 0; idx < inputs.size(); idx++) { const UniValue& input = inputs[idx]; @@ -975,7 +979,7 @@ static const CRPCCommand commands[] = { // category name actor (function) okSafeMode // --------------------- ------------------------ ----------------------- ---------- { "rawtransactions", "getrawtransaction", &getrawtransaction, true, {"txid","verbose"} }, - { "rawtransactions", "createrawtransaction", &createrawtransaction, true, {"inputs","outputs","locktime","replaceable"} }, + { "rawtransactions", "createrawtransaction", &createrawtransaction, true, {"inputs","outputs","locktime","replaceable","tx-comment"} }, { "rawtransactions", "decoderawtransaction", &decoderawtransaction, true, {"hexstring"} }, { "rawtransactions", "decodescript", &decodescript, true, {"hexstring"} }, { "rawtransactions", "sendrawtransaction", &sendrawtransaction, false, {"hexstring","allowhighfees"} }, diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 5f007c95d..c8352ac49 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -374,7 +374,7 @@ UniValue getaddressesbyaccount(const JSONRPCRequest& request) return ret; } -static void SendMoney(CWallet * const pwallet, const CTxDestination &address, CAmount nValue, bool fSubtractFeeFromAmount, CWalletTx& wtxNew, const CCoinControl& coin_control) +static void SendMoney(CWallet * const pwallet, const CTxDestination &address, CAmount nValue, bool fSubtractFeeFromAmount, CWalletTx& wtxNew, const CCoinControl& coin_control, std::string strTxComment) { CAmount curBalance = pwallet->GetBalance(); @@ -400,7 +400,7 @@ static void SendMoney(CWallet * const pwallet, const CTxDestination &address, CA int nChangePosRet = -1; CRecipient recipient = {scriptPubKey, nValue, fSubtractFeeFromAmount}; vecSend.push_back(recipient); - if (!pwallet->CreateTransaction(vecSend, wtxNew, reservekey, nFeeRequired, nChangePosRet, strError, coin_control)) { + if (!pwallet->CreateTransaction(vecSend, wtxNew, reservekey, nFeeRequired, nChangePosRet, strError, coin_control, strTxComment)) { if (!fSubtractFeeFromAmount && nValue + nFeeRequired > curBalance) strError = strprintf("Error: This transaction requires a transaction fee of at least %s", FormatMoney(nFeeRequired)); throw JSONRPCError(RPC_WALLET_ERROR, strError); @@ -419,9 +419,9 @@ UniValue sendtoaddress(const JSONRPCRequest& request) return NullUniValue; } - if (request.fHelp || request.params.size() < 2 || request.params.size() > 8) + if (request.fHelp || request.params.size() < 2 || request.params.size() > 9) throw std::runtime_error( - "sendtoaddress \"address\" amount ( \"comment\" \"comment_to\" subtractfeefromamount replaceable conf_target \"estimate_mode\")\n" + "sendtoaddress \"address\" amount ( \"comment\" \"comment_to\" subtractfeefromamount replaceable conf_target \"estimate_mode\" \"txcomment\")\n" "\nSend an amount to a given address.\n" + HelpRequiringPassphrase(pwallet) + "\nArguments:\n" @@ -440,6 +440,7 @@ UniValue sendtoaddress(const JSONRPCRequest& request) " \"UNSET\"\n" " \"ECONOMICAL\"\n" " \"CONSERVATIVE\"\n" + "9. tx-comment (string, optional) Transaction tx-comment (default = \"\").\n" "\nResult:\n" "\"txid\" (string) The transaction id.\n" "\nExamples:\n" @@ -487,10 +488,14 @@ UniValue sendtoaddress(const JSONRPCRequest& request) } } + std::string strTxComment = ""; + if (request.params.size() > 8 && !request.params[8].isNull()) { + strTxComment = request.params[8].get_str(); + } EnsureWalletIsUnlocked(pwallet); - SendMoney(pwallet, address.Get(), nAmount, fSubtractFeeFromAmount, wtx, coin_control); + SendMoney(pwallet, address.Get(), nAmount, fSubtractFeeFromAmount, wtx, coin_control, strTxComment); return wtx.GetHash().GetHex(); } @@ -860,7 +865,7 @@ UniValue sendfrom(const JSONRPCRequest& request) return NullUniValue; } - if (request.fHelp || request.params.size() < 3 || request.params.size() > 6) + if (request.fHelp || request.params.size() < 3 || request.params.size() > 7) throw std::runtime_error( "sendfrom \"fromaccount\" \"toaddress\" amount ( minconf \"comment\" \"comment_to\" )\n" "\nDEPRECATED (use sendtoaddress). Sent an amount from an account to a litecoin address." @@ -878,6 +883,7 @@ UniValue sendfrom(const JSONRPCRequest& request) "6. \"comment_to\" (string, optional) An optional comment to store the name of the person or organization \n" " to which you're sending the transaction. This is not part of the transaction, \n" " it is just kept in your wallet.\n" + "7. tx-comment (string, optional) Transaction comment (default = \"\").\n" "\nResult:\n" "\"txid\" (string) The transaction id.\n" "\nExamples:\n" @@ -909,6 +915,11 @@ UniValue sendfrom(const JSONRPCRequest& request) if (request.params.size() > 5 && !request.params[5].isNull() && !request.params[5].get_str().empty()) wtx.mapValue["to"] = request.params[5].get_str(); + std::string strTxComment = ""; + if (request.params.size() > 6 && !request.params[6].isNull()) { + strTxComment = request.params[6].get_str(); + } + EnsureWalletIsUnlocked(pwallet); // Check funds @@ -917,7 +928,7 @@ UniValue sendfrom(const JSONRPCRequest& request) throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds"); CCoinControl no_coin_control; // This is a deprecated API - SendMoney(pwallet, address.Get(), nAmount, false, wtx, no_coin_control); + SendMoney(pwallet, address.Get(), nAmount, false, wtx, no_coin_control, strTxComment); return wtx.GetHash().GetHex(); } @@ -930,7 +941,7 @@ UniValue sendmany(const JSONRPCRequest& request) return NullUniValue; } - if (request.fHelp || request.params.size() < 2 || request.params.size() > 8) + if (request.fHelp || request.params.size() < 2 || request.params.size() > 9) throw std::runtime_error( "sendmany \"fromaccount\" {\"address\":amount,...} ( minconf \"comment\" [\"address\",...] replaceable conf_target \"estimate_mode\")\n" "\nSend multiple times. Amounts are double-precision floating point numbers." @@ -958,7 +969,8 @@ UniValue sendmany(const JSONRPCRequest& request) " \"UNSET\"\n" " \"ECONOMICAL\"\n" " \"CONSERVATIVE\"\n" - "\nResult:\n" + "9. tx-comment (string, optional) Transaction comment (default = \"\").\n" + "\nResult:\n" "\"txid\" (string) The transaction id for the send. Only 1 transaction is created regardless of \n" " the number of addresses.\n" "\nExamples:\n" @@ -1008,6 +1020,11 @@ UniValue sendmany(const JSONRPCRequest& request) } } + std::string strTxComment = ""; + if (request.params.size() > 8 && !request.params[8].isNull()) { + strTxComment = request.params[8].get_str(); + } + std::set setAddress; std::vector vecSend; @@ -1052,7 +1069,7 @@ UniValue sendmany(const JSONRPCRequest& request) CAmount nFeeRequired = 0; int nChangePosRet = -1; std::string strFailReason; - bool fCreated = pwallet->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired, nChangePosRet, strFailReason, coin_control); + bool fCreated = pwallet->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired, nChangePosRet, strFailReason, coin_control, strTxComment); if (!fCreated) throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, strFailReason); CValidationState state; @@ -3192,9 +3209,9 @@ static const CRPCCommand commands[] = { "wallet", "listwallets", &listwallets, true, {} }, { "wallet", "lockunspent", &lockunspent, true, {"unlock","transactions"} }, { "wallet", "move", &movecmd, false, {"fromaccount","toaccount","amount","minconf","comment"} }, - { "wallet", "sendfrom", &sendfrom, false, {"fromaccount","toaddress","amount","minconf","comment","comment_to"} }, - { "wallet", "sendmany", &sendmany, false, {"fromaccount","amounts","minconf","comment","subtractfeefrom","replaceable","conf_target","estimate_mode"} }, - { "wallet", "sendtoaddress", &sendtoaddress, false, {"address","amount","comment","comment_to","subtractfeefromamount","replaceable","conf_target","estimate_mode"} }, + { "wallet", "sendfrom", &sendfrom, false, {"fromaccount","toaddress","amount","minconf","comment","comment_to","tx-comment"} }, + { "wallet", "sendmany", &sendmany, false, {"fromaccount","amounts","minconf","comment","subtractfeefrom","replaceable","conf_target","estimate_mode","tx-comment"} }, + { "wallet", "sendtoaddress", &sendtoaddress, false, {"address","amount","comment","comment_to","subtractfeefromamount","replaceable","conf_target","estimate_mode","tx-comment"} }, { "wallet", "setaccount", &setaccount, true, {"address","account"} }, { "wallet", "settxfee", &settxfee, true, {"amount"} }, { "wallet", "signmessage", &signmessage, true, {"address","message"} }, diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 318c159cf..b5ad8bc0a 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -30,6 +30,7 @@ #include "util.h" #include "ui_interface.h" #include "utilmoneystr.h" +#include "../primitives/transaction.h" #include @@ -2565,7 +2566,7 @@ bool CWallet::FundTransaction(CMutableTransaction& tx, CAmount& nFeeRet, int& nC CReserveKey reservekey(this); CWalletTx wtx; - if (!CreateTransaction(vecSend, wtx, reservekey, nFeeRet, nChangePosInOut, strFailReason, coinControl, false)) { + if (!CreateTransaction(vecSend, wtx, reservekey, nFeeRet, nChangePosInOut, strFailReason, coinControl, "", false)) { return false; } @@ -2611,7 +2612,7 @@ static CFeeRate GetDiscardRate(const CBlockPolicyEstimator& estimator) } bool CWallet::CreateTransaction(const std::vector& vecSend, CWalletTx& wtxNew, CReserveKey& reservekey, CAmount& nFeeRet, - int& nChangePosInOut, std::string& strFailReason, const CCoinControl& coin_control, bool sign) + int& nChangePosInOut, std::string& strFailReason, const CCoinControl& coin_control, std::string strTxComment, bool sign) { CAmount nValue = 0; int nChangePosRequest = nChangePosInOut; @@ -2638,6 +2639,8 @@ bool CWallet::CreateTransaction(const std::vector& vecSend, CWalletT wtxNew.BindWallet(this); CMutableTransaction txNew; + txNew.strTxComment = strTxComment; + // Discourage fee sniping. // // For a large miner the value of the transactions in the best block and diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 34472b40e..c9e6418fb 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -948,7 +948,7 @@ public: * @note passing nChangePosInOut as -1 will result in setting a random position */ bool CreateTransaction(const std::vector& vecSend, CWalletTx& wtxNew, CReserveKey& reservekey, CAmount& nFeeRet, int& nChangePosInOut, - std::string& strFailReason, const CCoinControl& coin_control, bool sign = true); + std::string& strFailReason, const CCoinControl& coin_control, std::string strTxComment = "", bool sign = true); bool CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey, CConnman* connman, CValidationState& state); void ListAccountCreditDebit(const std::string& strAccount, std::list& entries);