2021-04-20 21:33:02 +02:00
|
|
|
// Copyright (c) 2019-2021 The Dash Core developers
|
2019-12-31 15:22:17 +01:00
|
|
|
// Distributed under the MIT/X11 software license, see the accompanying
|
|
|
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
|
|
|
|
2022-04-05 11:09:41 +02:00
|
|
|
#include <node/context.h>
|
2020-03-19 23:46:56 +01:00
|
|
|
#include <validation.h>
|
2019-12-31 15:22:17 +01:00
|
|
|
#ifdef ENABLE_WALLET
|
2021-10-01 21:19:08 +02:00
|
|
|
#include <coinjoin/client.h>
|
|
|
|
#include <coinjoin/options.h>
|
2018-11-05 13:17:01 +01:00
|
|
|
#include <wallet/rpcwallet.h>
|
2019-12-31 15:22:17 +01:00
|
|
|
#endif // ENABLE_WALLET
|
2021-10-01 21:19:08 +02:00
|
|
|
#include <coinjoin/server.h>
|
2022-04-05 11:09:41 +02:00
|
|
|
#include <rpc/blockchain.h>
|
2020-03-19 23:46:56 +01:00
|
|
|
#include <rpc/server.h>
|
2021-10-11 23:55:23 +02:00
|
|
|
#include <rpc/util.h>
|
2021-06-27 08:33:13 +02:00
|
|
|
#include <util/strencodings.h>
|
2019-12-31 15:22:17 +01:00
|
|
|
|
|
|
|
#include <univalue.h>
|
|
|
|
|
|
|
|
#ifdef ENABLE_WALLET
|
2018-05-04 22:42:39 +02:00
|
|
|
static UniValue coinjoin(const JSONRPCRequest& request)
|
2019-12-31 15:22:17 +01:00
|
|
|
{
|
2021-10-11 23:55:23 +02:00
|
|
|
RPCHelpMan{"coinjoin",
|
2021-11-05 19:47:35 +01:00
|
|
|
"\nAvailable commands:\n"
|
|
|
|
" start - Start mixing\n"
|
|
|
|
" stop - Stop mixing\n"
|
|
|
|
" reset - Reset mixing",
|
2021-10-11 23:55:23 +02:00
|
|
|
{
|
2021-11-05 19:47:35 +01:00
|
|
|
{"command", RPCArg::Type::STR, RPCArg::Optional::NO, "The command to execute"},
|
|
|
|
},
|
|
|
|
RPCResults{},
|
|
|
|
RPCExamples{""},
|
2022-05-12 22:29:17 +02:00
|
|
|
}.Check(request);
|
2019-12-31 15:22:17 +01:00
|
|
|
|
2022-03-13 04:11:13 +01:00
|
|
|
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
|
|
|
|
if (!wallet) return NullUniValue;
|
|
|
|
CWallet* const pwallet = wallet.get();
|
|
|
|
|
2019-12-31 15:22:17 +01:00
|
|
|
if (fMasternodeMode)
|
|
|
|
throw JSONRPCError(RPC_INTERNAL_ERROR, "Client-side mixing is not supported on masternodes");
|
|
|
|
|
2021-03-17 23:36:11 +01:00
|
|
|
if (!CCoinJoinClientOptions::IsEnabled()) {
|
|
|
|
if (!gArgs.GetBoolArg("-enablecoinjoin", true)) {
|
2019-12-31 15:22:17 +01:00
|
|
|
// otherwise it's on by default, unless cmd line option says otherwise
|
2021-03-17 23:36:11 +01:00
|
|
|
throw JSONRPCError(RPC_INTERNAL_ERROR, "Mixing is disabled via -enablecoinjoin=0 command line option, remove it to enable mixing again");
|
2019-12-31 15:22:17 +01:00
|
|
|
} else {
|
2021-03-17 23:36:11 +01:00
|
|
|
// not enablecoinjoin=false case,
|
2020-01-08 08:02:49 +01:00
|
|
|
// most likely something bad happened and we disabled it while running the wallet
|
2019-12-31 15:22:17 +01:00
|
|
|
throw JSONRPCError(RPC_INTERNAL_ERROR, "Mixing is disabled due to some internal error");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-17 23:36:11 +01:00
|
|
|
auto it = coinJoinClientManagers.find(pwallet->GetName());
|
2020-07-16 14:23:58 +02:00
|
|
|
|
2019-12-31 15:22:17 +01:00
|
|
|
if (request.params[0].get_str() == "start") {
|
|
|
|
{
|
|
|
|
LOCK(pwallet->cs_wallet);
|
|
|
|
if (pwallet->IsLocked(true))
|
|
|
|
throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please unlock wallet for mixing with walletpassphrase first.");
|
|
|
|
}
|
|
|
|
|
2020-08-28 11:52:00 +02:00
|
|
|
if (!it->second->StartMixing()) {
|
2020-07-12 07:52:25 +02:00
|
|
|
throw JSONRPCError(RPC_INTERNAL_ERROR, "Mixing has been started already.");
|
|
|
|
}
|
|
|
|
|
2022-04-23 09:46:44 +02:00
|
|
|
NodeContext& node = EnsureNodeContext(request.context);
|
|
|
|
bool result = it->second->DoAutomaticDenominating(*node.connman);
|
2022-04-06 22:37:20 +02:00
|
|
|
return "Mixing " + (result ? "started successfully" : ("start failed: " + it->second->GetStatuses().original + ", will retry"));
|
2019-12-31 15:22:17 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (request.params[0].get_str() == "stop") {
|
2020-07-16 14:23:58 +02:00
|
|
|
it->second->StopMixing();
|
2019-12-31 15:22:17 +01:00
|
|
|
return "Mixing was stopped";
|
|
|
|
}
|
|
|
|
|
|
|
|
if (request.params[0].get_str() == "reset") {
|
2020-07-16 14:23:58 +02:00
|
|
|
it->second->ResetPool();
|
2019-12-31 15:22:17 +01:00
|
|
|
return "Mixing was reset";
|
|
|
|
}
|
|
|
|
|
2021-03-17 23:36:11 +01:00
|
|
|
return "Unknown command, please see \"help coinjoin\"";
|
2019-12-31 15:22:17 +01:00
|
|
|
}
|
|
|
|
#endif // ENABLE_WALLET
|
|
|
|
|
2018-05-04 22:42:39 +02:00
|
|
|
static UniValue getpoolinfo(const JSONRPCRequest& request)
|
2019-12-31 15:22:17 +01:00
|
|
|
{
|
|
|
|
throw std::runtime_error(
|
2021-10-11 23:55:23 +02:00
|
|
|
RPCHelpMan{"getpoolinfo",
|
|
|
|
"DEPRECATED. Please use getcoinjoininfo instead.\n",
|
2021-11-05 19:47:35 +01:00
|
|
|
{},
|
|
|
|
RPCResults{},
|
|
|
|
RPCExamples{""}}
|
|
|
|
.ToString());
|
2019-12-31 15:22:17 +01:00
|
|
|
}
|
|
|
|
|
2018-05-04 22:42:39 +02:00
|
|
|
static UniValue getcoinjoininfo(const JSONRPCRequest& request)
|
2019-12-31 15:22:17 +01:00
|
|
|
{
|
2021-10-11 23:55:23 +02:00
|
|
|
RPCHelpMan{"getcoinjoininfo",
|
|
|
|
"Returns an object containing an information about CoinJoin settings and state.\n",
|
2021-11-05 19:47:35 +01:00
|
|
|
{},
|
2022-05-12 22:29:17 +02:00
|
|
|
{
|
|
|
|
RPCResult{"for regular nodes",
|
|
|
|
RPCResult::Type::OBJ, "", "",
|
|
|
|
{
|
|
|
|
{RPCResult::Type::BOOL, "enabled", "Whether mixing functionality is enabled"},
|
|
|
|
{RPCResult::Type::BOOL, "multisession", "Whether CoinJoin Multisession option is enabled"},
|
|
|
|
{RPCResult::Type::NUM, "max_sessions", "How many parallel mixing sessions can there be at once"},
|
|
|
|
{RPCResult::Type::NUM, "max_rounds", "How many rounds to mix"},
|
|
|
|
{RPCResult::Type::NUM, "max_amount", "Target CoinJoin balance in " + CURRENCY_UNIT + ""},
|
|
|
|
{RPCResult::Type::NUM, "denoms_goal", "How many inputs of each denominated amount to target"},
|
|
|
|
{RPCResult::Type::NUM, "denoms_hardcap", "Maximum limit of how many inputs of each denominated amount to create"},
|
|
|
|
{RPCResult::Type::NUM, "queue_size", "How many queues there are currently on the network"},
|
|
|
|
{RPCResult::Type::BOOL, "running", "Whether mixing is currently running"},
|
|
|
|
{RPCResult::Type::ARR, "sessions", "",
|
|
|
|
{
|
|
|
|
{RPCResult::Type::OBJ, "", "",
|
|
|
|
{
|
|
|
|
{RPCResult::Type::STR_HEX, "protxhash", "The ProTxHash of the masternode"},
|
|
|
|
{RPCResult::Type::STR_HEX, "outpoint", "The outpoint of the masternode"},
|
|
|
|
{RPCResult::Type::STR, "service", "The IP address and port of the masternode"},
|
|
|
|
{RPCResult::Type::NUM, "denomination", "The denomination of the mixing session in " + CURRENCY_UNIT + ""},
|
|
|
|
{RPCResult::Type::STR_HEX, "state", "Current state of the mixing session"},
|
|
|
|
{RPCResult::Type::NUM, "entries_count", "The number of entries in the mixing session"},
|
|
|
|
}},
|
|
|
|
}},
|
|
|
|
{RPCResult::Type::NUM, "keys_left", "How many new keys are left since last automatic backup"},
|
|
|
|
{RPCResult::Type::STR, "warnings", "Warnings if any"},
|
|
|
|
}},
|
|
|
|
RPCResult{"for masternodes",
|
|
|
|
RPCResult::Type::OBJ, "", "",
|
|
|
|
{
|
|
|
|
{RPCResult::Type::NUM, "queue_size", "How many queues there are currently on the network"},
|
|
|
|
{RPCResult::Type::NUM, "denomination", "The denomination of the mixing session in " + CURRENCY_UNIT + ""},
|
|
|
|
{RPCResult::Type::STR_HEX, "state", "Current state of the mixing session"},
|
|
|
|
{RPCResult::Type::NUM, "entries_count", "The number of entries in the mixing session"},
|
|
|
|
}},
|
|
|
|
},
|
2021-11-05 19:47:35 +01:00
|
|
|
RPCExamples{
|
|
|
|
HelpExampleCli("getcoinjoininfo", "")
|
2021-10-11 23:55:23 +02:00
|
|
|
+ HelpExampleRpc("getcoinjoininfo", "")
|
2021-11-05 19:47:35 +01:00
|
|
|
},
|
2022-05-12 22:29:17 +02:00
|
|
|
}.Check(request);
|
2019-12-31 15:22:17 +01:00
|
|
|
|
|
|
|
UniValue obj(UniValue::VOBJ);
|
|
|
|
|
|
|
|
if (fMasternodeMode) {
|
2021-03-17 23:36:11 +01:00
|
|
|
coinJoinServer.GetJsonInfo(obj);
|
2019-12-31 15:22:17 +01:00
|
|
|
return obj;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef ENABLE_WALLET
|
2020-07-16 14:23:29 +02:00
|
|
|
|
2021-03-17 23:36:11 +01:00
|
|
|
CCoinJoinClientOptions::GetJsonInfo(obj);
|
2020-07-17 01:30:00 +02:00
|
|
|
|
2021-03-17 23:36:11 +01:00
|
|
|
obj.pushKV("queue_size", coinJoinClientQueueManager.GetQueueSize());
|
2019-12-31 15:22:17 +01:00
|
|
|
|
2021-04-01 19:28:43 +02:00
|
|
|
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
|
|
|
|
CWallet* const pwallet = wallet.get();
|
2019-12-31 15:22:17 +01:00
|
|
|
if (!pwallet) {
|
|
|
|
return obj;
|
|
|
|
}
|
|
|
|
|
2021-03-17 23:36:11 +01:00
|
|
|
coinJoinClientManagers.at(pwallet->GetName())->GetJsonInfo(obj);
|
2020-07-16 14:23:29 +02:00
|
|
|
|
2020-06-18 11:17:23 +02:00
|
|
|
obj.pushKV("keys_left", pwallet->nKeysLeftSinceAutoBackup);
|
2021-03-26 13:11:11 +01:00
|
|
|
obj.pushKV("warnings", pwallet->nKeysLeftSinceAutoBackup < COINJOIN_KEYS_THRESHOLD_WARNING
|
|
|
|
? "WARNING: keypool is almost depleted!" : "");
|
2019-12-31 15:22:17 +01:00
|
|
|
#endif // ENABLE_WALLET
|
|
|
|
|
|
|
|
return obj;
|
|
|
|
}
|
2018-09-10 18:13:11 +02:00
|
|
|
// clang-format off
|
2019-12-31 15:22:17 +01:00
|
|
|
static const CRPCCommand commands[] =
|
2017-09-05 18:43:07 +02:00
|
|
|
{ // category name actor (function) argNames
|
|
|
|
// --------------------- ------------------------ ---------------------------------
|
|
|
|
{ "dash", "getpoolinfo", &getpoolinfo, {} },
|
2021-03-17 23:36:11 +01:00
|
|
|
{ "dash", "getcoinjoininfo", &getcoinjoininfo, {} },
|
2019-12-31 15:22:17 +01:00
|
|
|
#ifdef ENABLE_WALLET
|
2021-03-17 23:36:11 +01:00
|
|
|
{ "dash", "coinjoin", &coinjoin, {} },
|
2019-12-31 15:22:17 +01:00
|
|
|
#endif // ENABLE_WALLET
|
|
|
|
};
|
2018-09-10 18:13:11 +02:00
|
|
|
// clang-format on
|
2021-03-17 23:36:11 +01:00
|
|
|
void RegisterCoinJoinRPCCommands(CRPCTable &t)
|
2019-12-31 15:22:17 +01:00
|
|
|
{
|
|
|
|
for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++)
|
|
|
|
t.appendCommand(commands[vcidx].name, &commands[vcidx]);
|
|
|
|
}
|