From bc6cbd2cbf1223e7506661bc439981df4ee28546 Mon Sep 17 00:00:00 2001 From: lateminer <9951982+lateminer@users.noreply.github.com> Date: Mon, 21 Oct 2019 20:37:25 +0300 Subject: [PATCH] RPC: add commands burn and burnwallet --- src/rpc/client.cpp | 2 + src/rpc/server.cpp | 4 +- src/rpc/server.h | 2 +- src/wallet/rpcwallet.cpp | 107 ++++++++++++++++++++++++++++++++++++--- 4 files changed, 107 insertions(+), 8 deletions(-) diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp index abd6cfb79..580376028 100644 --- a/src/rpc/client.cpp +++ b/src/rpc/client.cpp @@ -107,6 +107,8 @@ static const CRPCConvertParam vRPCConvertParams[] = { "getmempooldescendants", 1 }, { "reservebalance", 0}, { "reservebalance", 1}, + { "burn", 0 }, + { "burnwallet", 1 }, }; class CRPCConvertTable diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp index cc99c663d..5cb8ccc81 100644 --- a/src/rpc/server.cpp +++ b/src/rpc/server.cpp @@ -128,13 +128,15 @@ void RPCTypeCheckObj(const UniValue& o, } } -CAmount AmountFromValue(const UniValue& value) +CAmount AmountFromValue(const UniValue& value, bool allowZero) { if (!value.isNum() && !value.isStr()) throw JSONRPCError(RPC_TYPE_ERROR, "Amount is not a number or string"); CAmount amount; if (!ParseFixedPoint(value.getValStr(), 8, &amount)) throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount"); + if (amount == 0 && !allowZero) + throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount"); if (!MoneyRange(amount)) throw JSONRPCError(RPC_TYPE_ERROR, "Amount out of range"); return amount; diff --git a/src/rpc/server.h b/src/rpc/server.h index 86ab9bd88..42a4e7212 100644 --- a/src/rpc/server.h +++ b/src/rpc/server.h @@ -182,7 +182,7 @@ extern std::vector ParseHexV(const UniValue& v, std::string strNa extern std::vector ParseHexO(const UniValue& o, std::string strKey); extern int64_t nWalletUnlockTime; -extern CAmount AmountFromValue(const UniValue& value); +extern CAmount AmountFromValue(const UniValue& value, bool allowZero = false); extern UniValue ValueFromAmount(const CAmount& amount); extern double GetDifficulty(const CBlockIndex* blockindex = NULL); extern double GetPoSKernelPS(); diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 85a516c29..3784b5bdc 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -345,9 +345,7 @@ UniValue getaddressesbyaccount(const UniValue& params, bool fHelp) return ret; } - - -static void SendMoney(const CTxDestination &address, CAmount nValue, bool fSubtractFeeFromAmount, CWalletTx& wtxNew) +static void SendMoneyToScript(const CScript scriptPubKey, CAmount nValue, bool fSubtractFeeFromAmount, CWalletTx& wtxNew) { CAmount curBalance = pwalletMain->GetBalance(); @@ -364,9 +362,6 @@ static void SendMoney(const CTxDestination &address, CAmount nValue, bool fSubtr throw JSONRPCError(RPC_WALLET_ERROR, strError); } - // Parse Bitcoin address - CScript scriptPubKey = GetScriptForDestination(address); - // Create and send the transaction CReserveKey reservekey(pwalletMain); CAmount nFeeRequired; @@ -384,6 +379,14 @@ static void SendMoney(const CTxDestination &address, CAmount nValue, bool fSubtr throw JSONRPCError(RPC_WALLET_ERROR, "Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of the wallet and coins were spent in the copy but not marked as spent here."); } +static void SendMoney(const CTxDestination &address, CAmount nValue, bool fSubtractFeeFromAmount, CWalletTx& wtxNew) +{ + // Parse Bitcoin address + CScript scriptPubKey = GetScriptForDestination(address); + + SendMoneyToScript(scriptPubKey, nValue, fSubtractFeeFromAmount, wtxNew); +} + UniValue sendtoaddress(const UniValue& params, bool fHelp) { if (!EnsureWalletIsAvailable(fHelp)) @@ -2568,6 +2571,96 @@ UniValue fundrawtransaction(const UniValue& params, bool fHelp) return result; } +UniValue burn(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() < 1 || params.size() > 2) + throw runtime_error( + "burn [hex string]\n" + " is a real and is rounded to the nearest 0.00000001" + + HelpRequiringPassphrase()); + + CScript scriptPubKey; + + if (params.size() > 1) { + vector data; + if (params[1].get_str().size() > 0){ + data = ParseHexV(params[1], "data"); + } else { + // Empty data is valid + } + scriptPubKey = CScript() << OP_RETURN << data; + } else { + scriptPubKey = CScript() << OP_RETURN; + } + + CAmount nAmount = AmountFromValue(params[0], true); + CWalletTx wtx; + + EnsureWalletIsUnlocked(); + + SendMoneyToScript(scriptPubKey, nAmount, false, wtx); + + return wtx.GetHash().GetHex(); +} + +UniValue burnwallet(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() < 1 || params.size() > 2) + throw runtime_error( + "burnwallet [hex string] [force]" + + HelpRequiringPassphrase()); + + CScript scriptPubKey; + + if (params.size() > 0) { + vector data; + if (params[0].get_str().size() > 0){ + data = ParseHexV(params[0], "data"); + } else { + // Empty data is valid + } + scriptPubKey = CScript() << OP_RETURN << data; + } else { + scriptPubKey = CScript() << OP_RETURN; + } + + bool fForce = false; + if (params.size() > 1) + fForce = params[1].get_bool(); + + EnsureWalletIsUnlocked(); + + if (!fForce) { + if (scriptPubKey.size() <= 32) + throw JSONRPCError(RPC_WALLET_ERROR, "Warning: small data"); + if (pwalletMain->GetUnconfirmedBalance() != 0) + throw JSONRPCError(RPC_WALLET_ERROR, "Warning: unconfirmed balance != 0"); + if (pwalletMain->GetImmatureBalance() != 0) + throw JSONRPCError(RPC_WALLET_ERROR, "Warning: immature balance != 0"); + if (pwalletMain->GetStake() != 0) + throw JSONRPCError(RPC_WALLET_ERROR, "Warning: stake balance != 0"); + } + + CAmount nAmount = pwalletMain->GetBalance(); + std::vector vecSend; + CRecipient recipient = {scriptPubKey, nAmount, false}; + vecSend.push_back(recipient); + CWalletTx wtx; + CReserveKey keyChange(pwalletMain); + CAmount nFeeRequired = 0; + int nChangePosRet = -1; + std::string strError; + pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired, nChangePosRet, strError); + vecSend[0].nAmount -= nFeeRequired; + if (!pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired, nChangePosRet, strError)) + throw JSONRPCError(RPC_WALLET_ERROR, "Transaction creation failed"); + + if (!pwalletMain->CommitTransaction(wtx, keyChange)) + throw JSONRPCError(RPC_WALLET_ERROR, "Transaction commit failed"); + + return wtx.GetHash().GetHex(); +} + extern UniValue abortrescan(const UniValue& params, bool fHelp); // in rpcdump.cpp extern UniValue dumpprivkey(const UniValue& params, bool fHelp); // in rpcdump.cpp extern UniValue importprivkey(const UniValue& params, bool fHelp); @@ -2628,6 +2721,8 @@ static const CRPCCommand commands[] = { "wallet", "walletpassphrasechange", &walletpassphrasechange, true }, { "wallet", "walletpassphrase", &walletpassphrase, true }, { "wallet", "removeprunedfunds", &removeprunedfunds, true }, + { "wallet", "burn", &burn, false }, + { "wallet", "burnwallet", &burnwallet, false }, }; void RegisterWalletRPCCommands(CRPCTable &tableRPC)