Line data Source code
1 : // Copyright (c) 2019-2025 The Dash Core developers
2 : // Distributed under the MIT/X11 software license, see the accompanying
3 : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4 :
5 : #include <node/context.h>
6 : #include <rpc/server.h>
7 : #include <rpc/server_util.h>
8 : #include <rpc/util.h>
9 : #include <util/check.h>
10 : #include <wallet/receive.h>
11 : #include <wallet/rpc/util.h>
12 : #include <walletinitinterface.h>
13 :
14 : #include <active/context.h>
15 : #include <coinjoin/server.h>
16 : #include <coinjoin/walletman.h>
17 :
18 : #ifdef ENABLE_WALLET
19 : #include <coinjoin/options.h>
20 : #include <interfaces/coinjoin.h>
21 : #endif // ENABLE_WALLET
22 :
23 : #include <univalue.h>
24 :
25 : using node::NodeContext;
26 : #ifdef ENABLE_WALLET
27 : using wallet::CWallet;
28 : using wallet::GetWalletForJSONRPCRequest;
29 : using wallet::DEFAULT_DISABLE_WALLET;
30 : using wallet::WALLET_FLAG_DISABLE_PRIVATE_KEYS;
31 : #endif // ENABLE_WALLET
32 :
33 : #ifdef ENABLE_WALLET
34 : namespace {
35 0 : void ValidateCoinJoinArguments()
36 : {
37 : /* If CoinJoin is enabled, everything is working as expected, we can bail */
38 0 : if (CCoinJoinClientOptions::IsEnabled())
39 0 : return;
40 :
41 : /* CoinJoin is on by default, unless a command line argument says otherwise */
42 0 : if (!gArgs.GetBoolArg("-enablecoinjoin", true)) {
43 0 : throw JSONRPCError(RPC_INTERNAL_ERROR, "Mixing is disabled via -enablecoinjoin=0 command line option, remove it to enable mixing again");
44 : }
45 :
46 : /* Most likely something bad happened and we disabled it while running the wallet */
47 0 : throw JSONRPCError(RPC_INTERNAL_ERROR, "Mixing is disabled due to an internal error");
48 0 : }
49 : } // anonymous namespace
50 :
51 0 : static RPCHelpMan coinjoin()
52 : {
53 0 : return RPCHelpMan{"coinjoin",
54 0 : "\nAvailable commands:\n"
55 : " start - Start mixing\n"
56 : " status - Get mixing status\n"
57 : " stop - Stop mixing\n"
58 : " reset - Reset mixing",
59 0 : {
60 0 : {"command", RPCArg::Type::STR, RPCArg::Optional::NO, "The command to execute"},
61 : },
62 0 : RPCResult{RPCResult::Type::NONE, "", ""},
63 0 : RPCExamples{""},
64 0 : [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
65 : {
66 0 : throw JSONRPCError(RPC_INVALID_PARAMETER, "Must be a valid command");
67 0 : },
68 : };
69 0 : }
70 :
71 0 : static RPCHelpMan coinjoin_reset()
72 : {
73 0 : return RPCHelpMan{"coinjoin reset",
74 0 : "\nReset CoinJoin mixing\n",
75 0 : {},
76 0 : RPCResult{
77 0 : RPCResult::Type::STR, "", "Status of request"
78 : },
79 0 : RPCExamples{
80 0 : HelpExampleCli("coinjoin reset", "")
81 0 : + HelpExampleRpc("coinjoin reset", "")
82 : },
83 0 : [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
84 : {
85 0 : const std::shared_ptr<const CWallet> wallet = GetWalletForJSONRPCRequest(request);
86 0 : if (!wallet) return UniValue::VNULL;
87 :
88 0 : const NodeContext& node = EnsureAnyNodeContext(request.context);
89 :
90 0 : if (node.active_ctx) {
91 0 : throw JSONRPCError(RPC_INTERNAL_ERROR, "Client-side mixing is not supported on masternodes");
92 : }
93 :
94 0 : ValidateCoinJoinArguments();
95 :
96 0 : auto cj_clientman = CHECK_NONFATAL(node.coinjoin_loader)->GetClient(wallet->GetName());
97 0 : CHECK_NONFATAL(cj_clientman)->resetPool();
98 :
99 0 : return "Mixing was reset";
100 0 : },
101 : };
102 0 : }
103 :
104 0 : static RPCHelpMan coinjoin_start()
105 : {
106 0 : return RPCHelpMan{"coinjoin start",
107 0 : "\nStart CoinJoin mixing\n"
108 : "Wallet must be unlocked for mixing\n",
109 0 : {},
110 0 : RPCResult{
111 0 : RPCResult::Type::STR, "", "Status of request"
112 : },
113 0 : RPCExamples{
114 0 : HelpExampleCli("coinjoin start", "")
115 0 : + HelpExampleRpc("coinjoin start", "")
116 : },
117 0 : [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
118 : {
119 0 : const std::shared_ptr<const CWallet> wallet = GetWalletForJSONRPCRequest(request);
120 0 : if (!wallet) return UniValue::VNULL;
121 :
122 0 : const NodeContext& node = EnsureAnyNodeContext(request.context);
123 :
124 0 : if (node.active_ctx) {
125 0 : throw JSONRPCError(RPC_INTERNAL_ERROR, "Client-side mixing is not supported on masternodes");
126 : }
127 :
128 0 : ValidateCoinJoinArguments();
129 :
130 : {
131 0 : LOCK(wallet->cs_wallet);
132 0 : if (wallet->IsLocked(true))
133 0 : throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please unlock wallet for mixing with walletpassphrase first.");
134 0 : }
135 :
136 0 : auto cj_clientman = CHECK_NONFATAL(CHECK_NONFATAL(node.coinjoin_loader)->GetClient(wallet->GetName()));
137 0 : if (!cj_clientman->startMixing()) {
138 0 : throw JSONRPCError(RPC_INTERNAL_ERROR, "Mixing has been started already.");
139 : }
140 :
141 0 : return "Mixing requested";
142 0 : },
143 : };
144 0 : }
145 :
146 0 : static RPCHelpMan coinjoin_status()
147 : {
148 0 : return RPCHelpMan{"coinjoin status",
149 0 : "\nGet status on CoinJoin mixing sessions\n",
150 0 : {},
151 0 : RPCResult{
152 0 : RPCResult::Type::ARR, "", "",
153 0 : {{RPCResult::Type::STR, "", "Status of mixing session"}}},
154 0 : RPCExamples{
155 0 : HelpExampleCli("coinjoin status", "")
156 0 : + HelpExampleRpc("coinjoin status", "")
157 : },
158 0 : [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
159 : {
160 0 : const std::shared_ptr<const CWallet> wallet = GetWalletForJSONRPCRequest(request);
161 0 : if (!wallet) return UniValue::VNULL;
162 :
163 0 : const NodeContext& node = EnsureAnyNodeContext(request.context);
164 :
165 0 : if (node.active_ctx) {
166 0 : throw JSONRPCError(RPC_INTERNAL_ERROR, "Client-side mixing is not supported on masternodes");
167 : }
168 :
169 0 : ValidateCoinJoinArguments();
170 :
171 0 : auto cj_clientman = CHECK_NONFATAL(node.coinjoin_loader)->GetClient(wallet->GetName());
172 0 : if (!CHECK_NONFATAL(cj_clientman)->isMixing()) {
173 0 : throw JSONRPCError(RPC_INTERNAL_ERROR, "No ongoing mix session");
174 : }
175 :
176 0 : UniValue ret(UniValue::VARR);
177 0 : for (const auto& str_status : cj_clientman->getSessionStatuses()) {
178 0 : ret.push_back(str_status);
179 : }
180 0 : return ret;
181 0 : },
182 : };
183 0 : }
184 :
185 0 : static RPCHelpMan coinjoin_stop()
186 : {
187 0 : return RPCHelpMan{"coinjoin stop",
188 0 : "\nStop CoinJoin mixing\n",
189 0 : {},
190 0 : RPCResult{
191 0 : RPCResult::Type::STR, "", "Status of request"
192 : },
193 0 : RPCExamples{
194 0 : HelpExampleCli("coinjoin stop", "")
195 0 : + HelpExampleRpc("coinjoin stop", "")
196 : },
197 0 : [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
198 : {
199 0 : const std::shared_ptr<const CWallet> wallet = GetWalletForJSONRPCRequest(request);
200 0 : if (!wallet) return UniValue::VNULL;
201 :
202 0 : const NodeContext& node = EnsureAnyNodeContext(request.context);
203 :
204 0 : if (node.active_ctx) {
205 0 : throw JSONRPCError(RPC_INTERNAL_ERROR, "Client-side mixing is not supported on masternodes");
206 : }
207 :
208 0 : ValidateCoinJoinArguments();
209 :
210 0 : CHECK_NONFATAL(node.coinjoin_loader);
211 0 : auto cj_clientman = node.coinjoin_loader->GetClient(wallet->GetName());
212 :
213 0 : CHECK_NONFATAL(cj_clientman);
214 0 : if (!cj_clientman->isMixing()) {
215 0 : throw JSONRPCError(RPC_INTERNAL_ERROR, "No mix session to stop");
216 : }
217 0 : cj_clientman->stopMixing();
218 :
219 0 : return "Mixing was stopped";
220 0 : },
221 : };
222 0 : }
223 :
224 0 : static RPCHelpMan coinjoinsalt()
225 : {
226 0 : return RPCHelpMan{"coinjoinsalt",
227 0 : "\nAvailable commands:\n"
228 : " generate - Generate new CoinJoin salt\n"
229 : " get - Fetch existing CoinJoin salt\n"
230 : " set - Set new CoinJoin salt\n",
231 0 : {
232 0 : {"command", RPCArg::Type::STR, RPCArg::Optional::NO, "The command to execute"},
233 : },
234 0 : RPCResult{RPCResult::Type::NONE, "", ""},
235 0 : RPCExamples{""},
236 0 : [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
237 : {
238 0 : throw JSONRPCError(RPC_INVALID_PARAMETER, "Must be a valid command");
239 0 : },
240 : };
241 0 : }
242 :
243 0 : static RPCHelpMan coinjoinsalt_generate()
244 : {
245 0 : return RPCHelpMan{"coinjoinsalt generate",
246 0 : "\nGenerate new CoinJoin salt and store it in the wallet database\n"
247 : "Cannot generate new salt if CoinJoin mixing is in process or wallet has private keys disabled.\n",
248 0 : {
249 0 : {"overwrite", RPCArg::Type::BOOL, RPCArg::Default{false}, "Generate new salt even if there is an existing salt and/or there is CoinJoin balance"},
250 : },
251 0 : RPCResult{
252 0 : RPCResult::Type::BOOL, "", "Status of CoinJoin salt generation and commitment"
253 : },
254 0 : RPCExamples{
255 0 : HelpExampleCli("coinjoinsalt generate", "")
256 0 : + HelpExampleRpc("coinjoinsalt generate", "")
257 : },
258 0 : [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
259 : {
260 0 : std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
261 0 : if (!wallet) return UniValue::VNULL;
262 :
263 0 : const auto str_wallet = wallet->GetName();
264 0 : if (wallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
265 0 : throw JSONRPCError(RPC_INVALID_REQUEST,
266 0 : strprintf("Wallet \"%s\" has private keys disabled, cannot perform CoinJoin!", str_wallet));
267 : }
268 :
269 0 : bool enable_overwrite{false}; // Default value
270 0 : if (!request.params[0].isNull()) {
271 0 : enable_overwrite = ParseBoolV(request.params[0], "overwrite");
272 0 : }
273 :
274 0 : if (!enable_overwrite && !wallet->GetCoinJoinSalt().IsNull()) {
275 0 : throw JSONRPCError(RPC_INVALID_REQUEST,
276 0 : strprintf("Wallet \"%s\" already has set CoinJoin salt!", str_wallet));
277 : }
278 :
279 0 : const NodeContext& node = EnsureAnyNodeContext(request.context);
280 0 : if (node.coinjoin_loader != nullptr) {
281 0 : auto cj_clientman = node.coinjoin_loader->GetClient(wallet->GetName());
282 0 : if (cj_clientman != nullptr && cj_clientman->isMixing()) {
283 0 : throw JSONRPCError(RPC_WALLET_ERROR,
284 0 : strprintf("Wallet \"%s\" is currently mixing, cannot change salt!", str_wallet));
285 : }
286 0 : }
287 :
288 0 : const auto wallet_balance{GetBalance(*wallet)};
289 0 : const bool has_balance{(wallet_balance.m_anonymized
290 0 : + wallet_balance.m_denominated_trusted
291 0 : + wallet_balance.m_denominated_untrusted_pending) > 0};
292 0 : if (!enable_overwrite && has_balance) {
293 0 : throw JSONRPCError(RPC_WALLET_ERROR,
294 0 : strprintf("Wallet \"%s\" has CoinJoin balance, cannot continue!", str_wallet));
295 : }
296 :
297 0 : if (!wallet->SetCoinJoinSalt(GetRandHash())) {
298 0 : throw JSONRPCError(RPC_INVALID_REQUEST,
299 0 : strprintf("Unable to set new CoinJoin salt for wallet \"%s\"!", str_wallet));
300 : }
301 :
302 0 : wallet->ClearCoinJoinRoundsCache();
303 :
304 0 : return true;
305 0 : },
306 : };
307 0 : }
308 :
309 0 : static RPCHelpMan coinjoinsalt_get()
310 : {
311 0 : return RPCHelpMan{"coinjoinsalt get",
312 0 : "\nFetch existing CoinJoin salt\n"
313 : "Cannot fetch salt if wallet has private keys disabled.\n",
314 0 : {},
315 0 : RPCResult{
316 0 : RPCResult::Type::STR_HEX, "", "CoinJoin salt"
317 : },
318 0 : RPCExamples{
319 0 : HelpExampleCli("coinjoinsalt get", "")
320 0 : + HelpExampleRpc("coinjoinsalt get", "")
321 : },
322 0 : [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
323 : {
324 0 : std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
325 0 : if (!wallet) return UniValue::VNULL;
326 :
327 0 : const auto str_wallet = wallet->GetName();
328 0 : if (wallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
329 0 : throw JSONRPCError(RPC_INVALID_REQUEST,
330 0 : strprintf("Wallet \"%s\" has private keys disabled, cannot perform CoinJoin!", str_wallet));
331 : }
332 :
333 0 : const auto salt{wallet->GetCoinJoinSalt()};
334 0 : if (salt.IsNull()) {
335 0 : throw JSONRPCError(RPC_WALLET_ERROR,
336 0 : strprintf("Wallet \"%s\" has no CoinJoin salt!", str_wallet));
337 : }
338 0 : return salt.GetHex();
339 0 : },
340 : };
341 0 : }
342 :
343 0 : static RPCHelpMan coinjoinsalt_set()
344 : {
345 0 : return RPCHelpMan{"coinjoinsalt set",
346 0 : "\nSet new CoinJoin salt\n"
347 : "Cannot set salt if CoinJoin mixing is in process or wallet has private keys disabled.\n"
348 : "Will overwrite existing salt. The presence of a CoinJoin balance will cause the wallet to rescan.\n",
349 0 : {
350 0 : {"salt", RPCArg::Type::STR, RPCArg::Optional::NO, "Desired CoinJoin salt value for the wallet"},
351 0 : {"overwrite", RPCArg::Type::BOOL, RPCArg::Default{false}, "Overwrite salt even if CoinJoin balance present"},
352 : },
353 0 : RPCResult{
354 0 : RPCResult::Type::BOOL, "", "Status of CoinJoin salt change request"
355 : },
356 0 : RPCExamples{
357 0 : HelpExampleCli("coinjoinsalt set", "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16")
358 0 : + HelpExampleRpc("coinjoinsalt set", "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16")
359 : },
360 0 : [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
361 : {
362 0 : std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
363 0 : if (!wallet) return UniValue::VNULL;
364 :
365 0 : const auto salt{ParseHashV(request.params[0], "salt")};
366 0 : if (salt == uint256::ZERO) {
367 0 : throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid CoinJoin salt value");
368 : }
369 :
370 0 : bool enable_overwrite{false}; // Default value
371 0 : if (!request.params[1].isNull()) {
372 0 : enable_overwrite = ParseBoolV(request.params[1], "overwrite");
373 0 : }
374 :
375 0 : const auto str_wallet = wallet->GetName();
376 0 : if (wallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
377 0 : throw JSONRPCError(RPC_INVALID_REQUEST,
378 0 : strprintf("Wallet \"%s\" has private keys disabled, cannot perform CoinJoin!", str_wallet));
379 : }
380 :
381 0 : const NodeContext& node = EnsureAnyNodeContext(request.context);
382 0 : if (node.coinjoin_loader != nullptr) {
383 0 : auto cj_clientman = node.coinjoin_loader->GetClient(wallet->GetName());
384 0 : if (cj_clientman != nullptr && cj_clientman->isMixing()) {
385 0 : throw JSONRPCError(RPC_WALLET_ERROR,
386 0 : strprintf("Wallet \"%s\" is currently mixing, cannot change salt!", str_wallet));
387 : }
388 0 : }
389 :
390 0 : const auto wallet_balance{GetBalance(*wallet)};
391 0 : const bool has_balance{(wallet_balance.m_anonymized
392 0 : + wallet_balance.m_denominated_trusted
393 0 : + wallet_balance.m_denominated_untrusted_pending) > 0};
394 0 : if (has_balance && !enable_overwrite) {
395 0 : throw JSONRPCError(RPC_WALLET_ERROR,
396 0 : strprintf("Wallet \"%s\" has CoinJoin balance, cannot continue!", str_wallet));
397 : }
398 :
399 0 : if (!wallet->SetCoinJoinSalt(salt)) {
400 0 : throw JSONRPCError(RPC_WALLET_ERROR,
401 0 : strprintf("Unable to set new CoinJoin salt for wallet \"%s\"!", str_wallet));
402 : }
403 :
404 0 : wallet->ClearCoinJoinRoundsCache();
405 :
406 0 : return true;
407 0 : },
408 : };
409 0 : }
410 : #endif // ENABLE_WALLET
411 :
412 92 : static RPCHelpMan getcoinjoininfo()
413 : {
414 184 : return RPCHelpMan{"getcoinjoininfo",
415 92 : "Returns an object containing an information about CoinJoin settings and state.\n",
416 92 : {},
417 276 : {
418 184 : RPCResult{"for regular nodes",
419 92 : RPCResult::Type::OBJ, "", "",
420 1196 : {
421 92 : {RPCResult::Type::BOOL, "enabled", "Whether mixing functionality is enabled"},
422 92 : {RPCResult::Type::BOOL, "multisession", "Whether CoinJoin Multisession option is enabled"},
423 92 : {RPCResult::Type::NUM, "max_sessions", "How many parallel mixing sessions can there be at once"},
424 92 : {RPCResult::Type::NUM, "max_rounds", "How many rounds to mix"},
425 92 : {RPCResult::Type::NUM, "max_amount", "Target CoinJoin balance in " + CURRENCY_UNIT + ""},
426 92 : {RPCResult::Type::NUM, "denoms_goal", "How many inputs of each denominated amount to target"},
427 92 : {RPCResult::Type::NUM, "denoms_hardcap", "Maximum limit of how many inputs of each denominated amount to create"},
428 92 : {RPCResult::Type::NUM, "queue_size", "How many queues there are currently on the network"},
429 92 : {RPCResult::Type::BOOL, "running", "Whether mixing is currently running"},
430 184 : {RPCResult::Type::ARR, "sessions", "",
431 184 : {
432 184 : {RPCResult::Type::OBJ, "", "",
433 736 : {
434 92 : {RPCResult::Type::STR_HEX, "protxhash", "The ProTxHash of the masternode"},
435 92 : GetRpcResult("outpoint"),
436 92 : {RPCResult::Type::STR, "service", "The IP address and port of the masternode (DEPRECATED, returned only if config option -deprecatedrpc=service is passed)"},
437 184 : {RPCResult::Type::ARR, "addrs_core_p2p", "Network addresses of the masternode used for protocol P2P",
438 184 : {
439 92 : {RPCResult::Type::STR, "address", ""},
440 : }
441 : },
442 92 : {RPCResult::Type::NUM, "denomination", "The denomination of the mixing session in " + CURRENCY_UNIT + ""},
443 92 : {RPCResult::Type::STR_HEX, "state", "Current state of the mixing session"},
444 92 : {RPCResult::Type::NUM, "entries_count", "The number of entries in the mixing session"},
445 : }},
446 : }},
447 92 : {RPCResult::Type::NUM, "keys_left", /*optional=*/true, "How many new keys are left since last automatic backup (if applicable)"},
448 92 : {RPCResult::Type::STR, "warnings", "Warnings if any"},
449 : }},
450 184 : RPCResult{"for masternodes",
451 92 : RPCResult::Type::OBJ, "", "",
452 460 : {
453 92 : {RPCResult::Type::NUM, "queue_size", "How many queues there are currently on the network"},
454 92 : {RPCResult::Type::NUM, "denomination", "The denomination of the mixing session in " + CURRENCY_UNIT + ""},
455 92 : {RPCResult::Type::STR_HEX, "state", "Current state of the mixing session"},
456 92 : {RPCResult::Type::NUM, "entries_count", "The number of entries in the mixing session"},
457 : }},
458 : },
459 92 : RPCExamples{
460 92 : HelpExampleCli("getcoinjoininfo", "")
461 92 : + HelpExampleRpc("getcoinjoininfo", "")
462 : },
463 92 : [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
464 : {
465 0 : UniValue obj(UniValue::VOBJ);
466 :
467 0 : const NodeContext& node = EnsureAnyNodeContext(request.context);
468 0 : if (node.active_ctx) {
469 0 : node.active_ctx->GetCJServer().GetJsonInfo(obj);
470 0 : return obj;
471 : }
472 :
473 : #ifdef ENABLE_WALLET
474 0 : CCoinJoinClientOptions::GetJsonInfo(obj);
475 :
476 0 : if (node.cj_walletman) {
477 0 : if (auto queue_size = node.cj_walletman->getQueueSize()) {
478 0 : obj.pushKV("queue_size", queue_size.value());
479 0 : }
480 0 : }
481 :
482 0 : const std::shared_ptr<const CWallet> wallet = GetWalletForJSONRPCRequest(request);
483 0 : if (!wallet) {
484 0 : return obj;
485 : }
486 :
487 0 : auto cj_clientman = CHECK_NONFATAL(node.coinjoin_loader)->GetClient(wallet->GetName());
488 0 : CHECK_NONFATAL(cj_clientman)->getJsonInfo(obj);
489 :
490 0 : std::string warning_msg;
491 0 : if (wallet->IsLegacy()) {
492 0 : obj.pushKV("keys_left", wallet->nKeysLeftSinceAutoBackup);
493 0 : if (wallet->nKeysLeftSinceAutoBackup < COINJOIN_KEYS_THRESHOLD_WARNING) {
494 0 : warning_msg = "WARNING: keypool is almost depleted!";
495 0 : }
496 0 : }
497 0 : obj.pushKV("warnings", warning_msg);
498 : #endif // ENABLE_WALLET
499 :
500 0 : return obj;
501 0 : },
502 : };
503 0 : }
504 :
505 : #ifdef ENABLE_WALLET
506 0 : Span<const CRPCCommand> GetWalletCoinJoinRPCCommands()
507 : {
508 0 : static const CRPCCommand commands[]{
509 0 : {"dash", &coinjoin},
510 0 : {"dash", &coinjoin_reset},
511 0 : {"dash", &coinjoin_start},
512 0 : {"dash", &coinjoin_status},
513 0 : {"dash", &coinjoin_stop},
514 0 : {"dash", &coinjoinsalt},
515 0 : {"dash", &coinjoinsalt_generate},
516 0 : {"dash", &coinjoinsalt_get},
517 0 : {"dash", &coinjoinsalt_set},
518 0 : {"dash", &getcoinjoininfo},
519 : };
520 0 : return commands;
521 0 : }
522 : #endif // ENABLE_WALLET
523 :
524 178 : void RegisterCoinJoinRPCCommands(CRPCTable& t)
525 : {
526 224 : static const CRPCCommand commands_wallet[]{
527 46 : {"dash", &getcoinjoininfo},
528 : };
529 : // If we aren't compiling with wallet support, we still need to register RPCs that are
530 : // capable of working without wallet support. We have to do this even if wallet support
531 : // is compiled in but is disabled at runtime because runtime disablement prohibits
532 : // registering wallet RPCs. We still want the reduced functionality RPC to be registered.
533 : // TODO: Spin off these hybrid RPCs into dedicated wallet-only and/or wallet-free RPCs
534 : // and get rid of this workaround.
535 356 : if (!g_wallet_init_interface.HasWalletSupport()
536 : #ifdef ENABLE_WALLET
537 178 : || gArgs.GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET)
538 : #endif // ENABLE_WALLET
539 : ) {
540 0 : for (const auto& command : commands_wallet) {
541 0 : tableRPC.appendCommand(command.name, &command);
542 : }
543 0 : }
544 178 : }
|