1 // Copyright (c) 2014-2020 Daniel Kraft
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 <base58.h>
6 #include <coins.h>
7 #include <consensus/validation.h>
8 #include <init.h>
9 #include <interfaces/chain.h>
10 #include <key_io.h>
11 #include <names/common.h>
12 #include <names/encoding.h>
13 #include <names/main.h>
14 #include <names/mempool.h>
15 #include <node/context.h>
16 #include <net.h>
17 #include <primitives/transaction.h>
18 #include <random.h>
19 #include <rpc/blockchain.h>
20 #include <rpc/names.h>
21 #include <rpc/server.h>
22 #include <rpc/util.h>
23 #include <script/names.h>
24 #include <txmempool.h>
25 #include <util/fees.h>
26 #include <util/moneystr.h>
27 #include <util/system.h>
28 #include <util/translation.h>
29 #include <validation.h>
30 #include <wallet/coincontrol.h>
31 #include <wallet/rpcwallet.h>
32 #include <wallet/wallet.h>
33 
34 #include <univalue.h>
35 
36 #include <algorithm>
37 #include <memory>
38 
39 /* ************************************************************************** */
40 namespace
41 {
42 
43 /**
44  * A simple helper class that handles determination of the address to which
45  * name outputs should be sent.  It handles the CReserveKey reservation
46  * as well as parsing the explicit options given by the user (if any).
47  */
48 class DestinationAddressHelper
49 {
50 
51 private:
52 
53   /** Reference to the wallet that should be used.  */
54   CWallet& wallet;
55 
56   /**
57    * The reserve key that was used if no override is given.  When finalising
58    * (after the sending succeeded), this key needs to be marked as Keep().
59    */
60   std::unique_ptr<ReserveDestination> rdest;
61 
62   /** Set if a valid override destination was added.  */
63   std::unique_ptr<CTxDestination> overrideDest;
64 
65 public:
66 
DestinationAddressHelper(CWallet & w)67   explicit DestinationAddressHelper (CWallet& w)
68     : wallet(w)
69   {}
70 
71   /**
72    * Processes the given options object to see if it contains an override
73    * destination.  If it does, remembers it.
74    */
75   void setOptions (const UniValue& opt);
76 
77   /**
78    * Returns the script that should be used as destination.
79    */
80   CScript getScript ();
81 
82   /**
83    * Marks the key as used if one has been reserved.  This should be called
84    * when sending succeeded.
85    */
86   void finalise ();
87 
88 };
89 
setOptions(const UniValue & opt)90 void DestinationAddressHelper::setOptions (const UniValue& opt)
91 {
92   RPCTypeCheckObj (opt,
93     {
94       {"destAddress", UniValueType (UniValue::VSTR)},
95     },
96     true, false);
97   if (!opt.exists ("destAddress"))
98     return;
99 
100   CTxDestination dest = DecodeDestination (opt["destAddress"].get_str ());
101   if (!IsValidDestination (dest))
102     throw JSONRPCError (RPC_INVALID_ADDRESS_OR_KEY, "invalid address");
103   overrideDest.reset (new CTxDestination (std::move (dest)));
104 }
105 
getScript()106 CScript DestinationAddressHelper::getScript ()
107 {
108   if (overrideDest != nullptr)
109     return GetScriptForDestination (*overrideDest);
110 
111   rdest.reset (new ReserveDestination (&wallet, wallet.m_default_address_type));
112   CTxDestination dest;
113   if (!rdest->GetReservedDestination (dest, false))
114     throw JSONRPCError (RPC_WALLET_KEYPOOL_RAN_OUT,
115                         "Error: Keypool ran out,"
116                         " please call keypoolrefill first");
117 
118   return GetScriptForDestination (dest);
119 }
120 
finalise()121 void DestinationAddressHelper::finalise ()
122 {
123   if (rdest != nullptr)
124     rdest->KeepDestination ();
125 }
126 
127 /**
128  * Sends a name output to the given name script.  This is the "final" step that
129  * is common between name_new, name_firstupdate and name_update.  This method
130  * also implements the "sendCoins" option, if included.
131  */
132 UniValue
SendNameOutput(const JSONRPCRequest & request,CWallet & wallet,const CScript & nameOutScript,const CTxIn * nameInput,const UniValue & opt)133 SendNameOutput (const JSONRPCRequest& request,
134                 CWallet& wallet, const CScript& nameOutScript,
135                 const CTxIn* nameInput, const UniValue& opt)
136 {
137   RPCTypeCheckObj (opt,
138     {
139       {"sendCoins", UniValueType (UniValue::VOBJ)},
140     },
141     true, false);
142 
143   auto& node = EnsureNodeContext (request.context);
144   if (wallet.GetBroadcastTransactions () && !node.connman)
145     throw JSONRPCError (RPC_CLIENT_P2P_DISABLED,
146                         "Error: Peer-to-peer functionality missing"
147                         " or disabled");
148 
149   std::vector<CRecipient> vecSend;
150   vecSend.push_back ({nameOutScript, NAME_LOCKED_AMOUNT, false});
151 
152   if (opt.exists ("sendCoins"))
153     for (const std::string& addr : opt["sendCoins"].getKeys ())
154       {
155         const CTxDestination dest = DecodeDestination (addr);
156         if (!IsValidDestination (dest))
157           throw JSONRPCError (RPC_INVALID_ADDRESS_OR_KEY,
158                               "Invalid address: " + addr);
159 
160         const CAmount nAmount = AmountFromValue (opt["sendCoins"][addr]);
161         if (nAmount <= 0)
162           throw JSONRPCError (RPC_TYPE_ERROR, "Invalid amount for send");
163 
164         vecSend.push_back ({GetScriptForDestination (dest), nAmount, false});
165       }
166 
167   CCoinControl coinControl;
168   return SendMoney (&wallet, coinControl, nameInput, vecSend, {}, false);
169 }
170 
171 } // anonymous namespace
172 /* ************************************************************************** */
173 
174 RPCHelpMan
name_list()175 name_list ()
176 {
177   NameOptionsHelp optHelp;
178   optHelp
179       .withNameEncoding ()
180       .withValueEncoding ();
181 
182   return RPCHelpMan ("name_list",
183       "\nShows the status of all names in the wallet.\n",
184       {
185           {"name", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, "Only include this name"},
186           optHelp.buildRpcArg (),
187       },
188       RPCResult {RPCResult::Type::ARR, "", "",
189           {
190               NameInfoHelp ()
191                 .withExpiration ()
192                 .finish ()
193           }
194       },
195       RPCExamples {
196           HelpExampleCli ("name_list", "")
197         + HelpExampleCli ("name_list", "\"myname\"")
198         + HelpExampleRpc ("name_list", "")
199       },
200       [&] (const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
201 {
202   std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest (request);
203   if (!wallet)
204     return NullUniValue;
205   CWallet* const pwallet = wallet.get ();
206 
207   RPCTypeCheck (request.params, {UniValue::VSTR, UniValue::VOBJ}, true);
208 
209   UniValue options(UniValue::VOBJ);
210   if (request.params.size () >= 2)
211     options = request.params[1].get_obj ();
212 
213   valtype nameFilter;
214   if (request.params.size () >= 1 && !request.params[0].isNull ())
215     nameFilter = DecodeNameFromRPCOrThrow (request.params[0], options);
216 
217   std::map<valtype, int> mapHeights;
218   std::map<valtype, UniValue> mapObjects;
219 
220   /* Make sure the results are valid at least up to the most recent block
221      the user could have gotten from another RPC command prior to now.  */
222   pwallet->BlockUntilSyncedToCurrentChain ();
223 
224   {
225   LOCK2 (pwallet->cs_wallet, cs_main);
226 
227   const int tipHeight = ::ChainActive ().Height ();
228   for (const auto& item : pwallet->mapWallet)
229     {
230       const CWalletTx& tx = item.second;
231       if (!tx.tx->IsNamecoin ())
232         continue;
233 
234       CNameScript nameOp;
235       int nOut = -1;
236       for (unsigned i = 0; i < tx.tx->vout.size (); ++i)
237         {
238           const CNameScript cur(tx.tx->vout[i].scriptPubKey);
239           if (cur.isNameOp ())
240             {
241               if (nOut != -1)
242                 LogPrintf ("ERROR: wallet contains tx with multiple"
243                            " name outputs");
244               else
245                 {
246                   nameOp = cur;
247                   nOut = i;
248                 }
249             }
250         }
251 
252       if (nOut == -1 || !nameOp.isAnyUpdate ())
253         continue;
254 
255       const valtype& name = nameOp.getOpName ();
256       if (!nameFilter.empty () && nameFilter != name)
257         continue;
258 
259       const int depth = tx.GetDepthInMainChain ();
260       if (depth <= 0)
261         continue;
262       const int height = tipHeight - depth + 1;
263 
264       const auto mit = mapHeights.find (name);
265       if (mit != mapHeights.end () && mit->second > height)
266         continue;
267 
268       UniValue obj
269         = getNameInfo (options, name, nameOp.getOpValue (),
270                        COutPoint (tx.GetHash (), nOut),
271                        nameOp.getAddress ());
272       addOwnershipInfo (nameOp.getAddress (), pwallet, obj);
273       addExpirationInfo (height, obj);
274 
275       mapHeights[name] = height;
276       mapObjects[name] = obj;
277     }
278   }
279 
280   UniValue res(UniValue::VARR);
281   for (const auto& item : mapObjects)
282     res.push_back (item.second);
283 
284   return res;
285 }
286   );
287 }
288 
289 /* ************************************************************************** */
290 
291 RPCHelpMan
name_new()292 name_new ()
293 {
294   NameOptionsHelp optHelp;
295   optHelp
296       .withNameEncoding ()
297       .withWriteOptions ()
298       .withArg ("allowExisting", RPCArg::Type::BOOL, "false",
299                 "If set, then the name_new is sent even if the name exists already");
300 
301   return RPCHelpMan ("name_new",
302       "\nStarts registration of the given name.  Must be followed up with name_firstupdate to finish the registration."
303           + HELP_REQUIRING_PASSPHRASE,
304       {
305           {"name", RPCArg::Type::STR, RPCArg::Optional::NO, "The name to register"},
306           optHelp.buildRpcArg (),
307       },
308       RPCResult {RPCResult::Type::ARR_FIXED, "", "",
309           {
310               {RPCResult::Type::STR_HEX, "txid", "the txid, required for name_firstupdate"},
311               {RPCResult::Type::STR_HEX, "rand", "random value, for name_firstupdate"},
312           },
313       },
314       RPCExamples {
315           HelpExampleCli ("name_new", "\"myname\"")
316         + HelpExampleRpc ("name_new", "\"myname\"")
317       },
318       [&] (const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
319 {
320   std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest (request);
321   if (!wallet)
322     return NullUniValue;
323   CWallet* const pwallet = wallet.get ();
324 
325   RPCTypeCheck (request.params, {UniValue::VSTR, UniValue::VOBJ});
326 
327   UniValue options(UniValue::VOBJ);
328   if (request.params.size () >= 2)
329     options = request.params[1].get_obj ();
330   RPCTypeCheckObj (options,
331     {
332       {"allowExisting", UniValueType (UniValue::VBOOL)},
333     },
334     true, false);
335 
336   const valtype name = DecodeNameFromRPCOrThrow (request.params[0], options);
337   if (name.size () > MAX_NAME_LENGTH)
338     throw JSONRPCError (RPC_INVALID_PARAMETER, "the name is too long");
339 
340   if (!options["allowExisting"].isTrue ())
341     {
342       LOCK (cs_main);
343       CNameData oldData;
344       const auto& coinsTip = ::ChainstateActive ().CoinsTip ();
345       if (coinsTip.GetName (name, oldData) && !oldData.isExpired ())
346         throw JSONRPCError (RPC_TRANSACTION_ERROR, "this name exists already");
347     }
348 
349   valtype rand(20);
350   GetRandBytes (&rand[0], rand.size ());
351 
352   /* Make sure the results are valid at least up to the most recent block
353      the user could have gotten from another RPC command prior to now.  */
354   pwallet->BlockUntilSyncedToCurrentChain ();
355 
356   LOCK (pwallet->cs_wallet);
357 
358   EnsureWalletIsUnlocked (pwallet);
359 
360   DestinationAddressHelper destHelper(*pwallet);
361   destHelper.setOptions (options);
362 
363   const CScript newScript
364       = CNameScript::buildNameNew (destHelper.getScript (), name, rand);
365 
366   const UniValue txidVal
367       = SendNameOutput (request, *pwallet, newScript, nullptr, options);
368   destHelper.finalise ();
369 
370   const std::string randStr = HexStr (rand);
371   const std::string txid = txidVal.get_str ();
372   LogPrintf ("name_new: name=%s, rand=%s, tx=%s\n",
373              EncodeNameForMessage (name), randStr.c_str (), txid.c_str ());
374 
375   UniValue res(UniValue::VARR);
376   res.push_back (txid);
377   res.push_back (randStr);
378 
379   return res;
380 }
381   );
382 }
383 
384 /* ************************************************************************** */
385 
386 namespace
387 {
388 
389 /**
390  * Helper routine to fetch the name output of a previous transaction.  This
391  * is required for name_firstupdate.
392  * @param txid Previous transaction ID.
393  * @param txOut Set to the corresponding output.
394  * @param txIn Set to the CTxIn to include in the new tx.
395  * @return True if the output could be found.
396  */
397 bool
getNamePrevout(const uint256 & txid,CTxOut & txOut,CTxIn & txIn)398 getNamePrevout (const uint256& txid, CTxOut& txOut, CTxIn& txIn)
399 {
400   AssertLockHeld (cs_main);
401 
402   // Maximum number of outputs that are checked for the NAME_NEW prevout.
403   constexpr unsigned MAX_NAME_PREVOUT_TRIALS = 1000;
404 
405   // Unfortunately, with the change of the txdb to be based on outputs rather
406   // than full transactions, we can no longer just look up the txid and iterate
407   // over all outputs.  Since this is only necessary for a corner case, we just
408   // keep trying with indices until we find the output (up to a maximum number
409   // of trials).
410 
411   for (unsigned i = 0; i < MAX_NAME_PREVOUT_TRIALS; ++i)
412     {
413       const COutPoint outp(txid, i);
414 
415       Coin coin;
416       if (!::ChainstateActive ().CoinsTip ().GetCoin (outp, coin))
417         continue;
418 
419       if (!coin.out.IsNull ()
420           && CNameScript::isNameScript (coin.out.scriptPubKey))
421         {
422           txOut = coin.out;
423           txIn = CTxIn (outp);
424           return true;
425         }
426     }
427 
428   return false;
429 }
430 
431 }  // anonymous namespace
432 
433 UniValue
name_firstupdate(const JSONRPCRequest & request)434 name_firstupdate (const JSONRPCRequest& request)
435 {
436   /* There is an undocumented sixth argument that can be used to disable
437      the check for already existing names here (it will still be checked
438      by the mempool and tx validation logic, of course).  This is used
439      by the regtests to catch a bug that was previously present but
440      has presumably no other use.  */
441 
442   NameOptionsHelp optHelp;
443   optHelp
444       .withNameEncoding ()
445       .withValueEncoding ()
446       .withWriteOptions ();
447 
448   /* We can not use RPCHelpMan::Check here, as we have that "hidden" sixth
449      argument for "allow active" names (in tests).  */
450   if (request.fHelp || request.params.size () < 3 || request.params.size () > 6)
451     throw std::runtime_error (
452         RPCHelpMan ("name_firstupdate",
453             "\nFinishes the registration of a name.  Depends on name_new being already issued."
454                 + HELP_REQUIRING_PASSPHRASE,
455             {
456                 {"name", RPCArg::Type::STR, RPCArg::Optional::NO, "The name to register"},
457                 {"rand", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The rand value of name_new"},
458                 {"tx", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The name_new txid"},
459                 {"value", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, "Value for the name"},
460                 optHelp.buildRpcArg (),
461             },
462             RPCResult {RPCResult::Type::STR_HEX, "", "the transaction ID"},
463             RPCExamples {
464                 HelpExampleCli ("name_firstupdate", "\"myname\", \"555844f2db9c7f4b25da6cb8277596de45021ef2\" \"a77ceb22aa03304b7de64ec43328974aeaca211c37dd29dcce4ae461bb80ca84\", \"my-value\"")
465               + HelpExampleRpc ("name_firstupdate", "\"myname\", \"555844f2db9c7f4b25da6cb8277596de45021ef2\" \"a77ceb22aa03304b7de64ec43328974aeaca211c37dd29dcce4ae461bb80ca84\", \"my-value\"")
466             }
467         ).ToString ());
468 
469   std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest (request);
470   if (!wallet)
471     return NullUniValue;
472   CWallet* const pwallet = wallet.get ();
473 
474   RPCTypeCheck (request.params,
475                 {UniValue::VSTR, UniValue::VSTR, UniValue::VSTR, UniValue::VSTR,
476                  UniValue::VOBJ}, true);
477 
478   UniValue options(UniValue::VOBJ);
479   if (request.params.size () >= 5)
480     options = request.params[4].get_obj ();
481 
482   const valtype name = DecodeNameFromRPCOrThrow (request.params[0], options);
483   if (name.size () > MAX_NAME_LENGTH)
484     throw JSONRPCError (RPC_INVALID_PARAMETER, "the name is too long");
485 
486   const valtype rand = ParseHexV (request.params[1], "rand");
487   if (rand.size () > 20)
488     throw JSONRPCError (RPC_INVALID_PARAMETER, "invalid rand value");
489 
490   const uint256 prevTxid = ParseHashV (request.params[2], "txid");
491 
492   const bool isDefaultVal = (request.params.size () < 4 || request.params[3].isNull ());
493   const valtype value = isDefaultVal ?
494       valtype ():
495       DecodeValueFromRPCOrThrow (request.params[3], options);
496 
497   if (value.size () > MAX_VALUE_LENGTH_UI)
498     throw JSONRPCError (RPC_INVALID_PARAMETER, "the value is too long");
499 
500   {
501     auto& mempool = EnsureMemPool (request.context);
502     LOCK (mempool.cs);
503     if (mempool.registersName (name))
504       throw JSONRPCError (RPC_TRANSACTION_ERROR,
505                           "this name is already being registered");
506   }
507 
508   if (request.params.size () < 6 || !request.params[5].get_bool ())
509     {
510       LOCK (cs_main);
511       CNameData oldData;
512       const auto& coinsTip = ::ChainstateActive ().CoinsTip ();
513       if (coinsTip.GetName (name, oldData) && !oldData.isExpired ())
514         throw JSONRPCError (RPC_TRANSACTION_ERROR,
515                             "this name is already active");
516     }
517 
518   CTxOut prevOut;
519   CTxIn txIn;
520   {
521     LOCK (cs_main);
522     if (!getNamePrevout (prevTxid, prevOut, txIn))
523       throw JSONRPCError (RPC_TRANSACTION_ERROR, "previous txid not found");
524   }
525 
526   const CNameScript prevNameOp(prevOut.scriptPubKey);
527   assert (prevNameOp.isNameOp ());
528   if (prevNameOp.getNameOp () != OP_NAME_NEW)
529     throw JSONRPCError (RPC_TRANSACTION_ERROR, "previous tx is not name_new");
530 
531   valtype toHash(rand);
532   toHash.insert (toHash.end (), name.begin (), name.end ());
533   if (uint160 (prevNameOp.getOpHash ()) != Hash160 (toHash))
534     throw JSONRPCError (RPC_TRANSACTION_ERROR, "rand value is wrong");
535 
536   /* Make sure the results are valid at least up to the most recent block
537      the user could have gotten from another RPC command prior to now.  */
538   pwallet->BlockUntilSyncedToCurrentChain ();
539 
540   LOCK (pwallet->cs_wallet);
541 
542   EnsureWalletIsUnlocked (pwallet);
543 
544   DestinationAddressHelper destHelper(*pwallet);
545   destHelper.setOptions (options);
546 
547   const CScript nameScript
548     = CNameScript::buildNameFirstupdate (destHelper.getScript (), name, value,
549                                          rand);
550 
551   const UniValue txidVal
552       = SendNameOutput (request, *pwallet, nameScript, &txIn, options);
553   destHelper.finalise ();
554 
555   return txidVal;
556 }
557 
558 /* ************************************************************************** */
559 
560 RPCHelpMan
name_update()561 name_update ()
562 {
563   NameOptionsHelp optHelp;
564   optHelp
565       .withNameEncoding ()
566       .withValueEncoding ()
567       .withWriteOptions ();
568 
569   return RPCHelpMan ("name_update",
570       "\nUpdates a name and possibly transfers it."
571           + HELP_REQUIRING_PASSPHRASE,
572       {
573           {"name", RPCArg::Type::STR, RPCArg::Optional::NO, "The name to update"},
574           {"value", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, "Value for the name"},
575           optHelp.buildRpcArg (),
576       },
577       RPCResult {RPCResult::Type::STR_HEX, "", "the transaction ID"},
578       RPCExamples {
579           HelpExampleCli ("name_update", "\"myname\", \"new-value\"")
580         + HelpExampleRpc ("name_update", "\"myname\", \"new-value\"")
581       },
582       [&] (const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
583 {
584   std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest (request);
585   if (!wallet)
586     return NullUniValue;
587   CWallet* const pwallet = wallet.get ();
588 
589   RPCTypeCheck (request.params,
590                 {UniValue::VSTR, UniValue::VSTR, UniValue::VOBJ}, true);
591 
592   UniValue options(UniValue::VOBJ);
593   if (request.params.size () >= 3)
594     options = request.params[2].get_obj ();
595 
596   const valtype name = DecodeNameFromRPCOrThrow (request.params[0], options);
597   if (name.size () > MAX_NAME_LENGTH)
598     throw JSONRPCError (RPC_INVALID_PARAMETER, "the name is too long");
599 
600   const bool isDefaultVal = request.params.size() < 2 || request.params[1].isNull();
601 
602   valtype value;
603   if (!isDefaultVal) {
604       value = DecodeValueFromRPCOrThrow (request.params[1], options);
605       if (value.size () > MAX_VALUE_LENGTH_UI)
606           throw JSONRPCError (RPC_INVALID_PARAMETER, "the value is too long");
607   }
608 
609   /* For finding the name output to spend and its value, we first check if
610      there are pending operations on the name in the mempool.  If there
611      are, then we build upon the last one to get a valid chain.  If there
612      are none, then we look up the last outpoint from the name database
613      instead. */
614   // TODO: Use name_show for this instead.
615 
616   const unsigned chainLimit = gArgs.GetArg ("-limitnamechains",
617                                             DEFAULT_NAME_CHAIN_LIMIT);
618   COutPoint outp;
619   {
620     auto& mempool = EnsureMemPool (request.context);
621     LOCK (mempool.cs);
622 
623     const unsigned pendingOps = mempool.pendingNameChainLength (name);
624     if (pendingOps >= chainLimit)
625       throw JSONRPCError (RPC_TRANSACTION_ERROR,
626                           "there are already too many pending operations"
627                           " on this name");
628 
629     if (pendingOps > 0)
630       {
631         outp = mempool.lastNameOutput (name);
632         if (isDefaultVal)
633           {
634             const auto& tx = mempool.mapTx.find(outp.hash)->GetTx();
635             value = CNameScript(tx.vout[outp.n].scriptPubKey).getOpValue();
636           }
637       }
638   }
639 
640   if (outp.IsNull ())
641     {
642       LOCK (cs_main);
643 
644       CNameData oldData;
645       const auto& coinsTip = ::ChainstateActive ().CoinsTip ();
646       if (!coinsTip.GetName (name, oldData) || oldData.isExpired ())
647         throw JSONRPCError (RPC_TRANSACTION_ERROR,
648                             "this name can not be updated");
649       if (isDefaultVal)
650         value = oldData.getValue();
651       outp = oldData.getUpdateOutpoint ();
652     }
653   assert (!outp.IsNull ());
654   const CTxIn txIn(outp);
655 
656   /* Make sure the results are valid at least up to the most recent block
657      the user could have gotten from another RPC command prior to now.  */
658   pwallet->BlockUntilSyncedToCurrentChain ();
659 
660   LOCK (pwallet->cs_wallet);
661 
662   EnsureWalletIsUnlocked (pwallet);
663 
664   DestinationAddressHelper destHelper(*pwallet);
665   destHelper.setOptions (options);
666 
667   const CScript nameScript
668     = CNameScript::buildNameUpdate (destHelper.getScript (), name, value);
669 
670   const UniValue txidVal
671       = SendNameOutput (request, *pwallet, nameScript, &txIn, options);
672   destHelper.finalise ();
673 
674   return txidVal;
675 }
676   );
677 }
678 
679 /* ************************************************************************** */
680 
681 RPCHelpMan
sendtoname()682 sendtoname ()
683 {
684   return RPCHelpMan{"sendtoname",
685       "\nSend an amount to the owner of a name.\n"
686       "\nIt is an error if the name is expired."
687           + HELP_REQUIRING_PASSPHRASE,
688       {
689           {"name", RPCArg::Type::STR, RPCArg::Optional::NO, "The name to send to."},
690           {"amount", RPCArg::Type::AMOUNT, RPCArg::Optional::NO, "The amount in " + CURRENCY_UNIT + " to send. eg 0.1"},
691           {"comment", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, "A comment used to store what the transaction is for.\n"
692   "                             This is not part of the transaction, just kept in your wallet."},
693           {"comment_to", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, "A comment to store the name of the person or organization\n"
694   "                             to which you're sending the transaction. This is not part of the \n"
695   "                             transaction, just kept in your wallet."},
696           {"subtractfeefromamount", RPCArg::Type::BOOL, /* default */ "false", "The fee will be deducted from the amount being sent.\n"
697   "                             The recipient will receive less coins than you enter in the amount field."},
698           {"replaceable", RPCArg::Type::BOOL, /* default */ "fallback to wallet's default", "Allow this transaction to be replaced by a transaction with higher fees via BIP 125"},
699       },
700           RPCResult {RPCResult::Type::STR_HEX, "", "the transaction ID"},
701           RPCExamples{
702               HelpExampleCli ("sendtoname", "\"id/foobar\" 0.1")
703       + HelpExampleCli ("sendtoname", "\"id/foobar\" 0.1 \"donation\" \"seans outpost\"")
704       + HelpExampleCli ("sendtoname", "\"id/foobar\" 0.1 \"\" \"\" true")
705       + HelpExampleRpc ("sendtoname", "\"id/foobar\", 0.1, \"donation\", \"seans outpost\"")
706           },
707       [&] (const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
708 {
709   std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest (request);
710   if (!wallet)
711     return NullUniValue;
712   CWallet* const pwallet = wallet.get ();
713 
714   if (::ChainstateActive ().IsInitialBlockDownload ())
715     throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD,
716                        "Namecoin is downloading blocks...");
717 
718   /* Make sure the results are valid at least up to the most recent block
719      the user could have gotten from another RPC command prior to now.  */
720   pwallet->BlockUntilSyncedToCurrentChain();
721 
722   LOCK(pwallet->cs_wallet);
723 
724   /* sendtoname does not support an options argument (e.g. to override the
725      configured name/value encodings).  That would just add to the already
726      long list of rarely used arguments.  Also, this function is inofficially
727      deprecated anyway, see
728      https://github.com/namecoin/namecoin-core/issues/12.  */
729   const UniValue NO_OPTIONS(UniValue::VOBJ);
730 
731   const valtype name = DecodeNameFromRPCOrThrow (request.params[0], NO_OPTIONS);
732 
733   CNameData data;
734   if (!::ChainstateActive ().CoinsTip ().GetName (name, data))
735     {
736       std::ostringstream msg;
737       msg << "name not found: " << EncodeNameForMessage (name);
738       throw JSONRPCError (RPC_INVALID_ADDRESS_OR_KEY, msg.str ());
739     }
740   if (data.isExpired ())
741     throw JSONRPCError (RPC_INVALID_ADDRESS_OR_KEY, "the name is expired");
742 
743   /* The code below is strongly based on sendtoaddress.  Make sure to
744      keep it in sync.  */
745 
746   // Wallet comments
747   mapValue_t mapValue;
748   if (request.params.size() > 2 && !request.params[2].isNull()
749         && !request.params[2].get_str().empty())
750       mapValue["comment"] = request.params[2].get_str();
751   if (request.params.size() > 3 && !request.params[3].isNull()
752         && !request.params[3].get_str().empty())
753       mapValue["to"] = request.params[3].get_str();
754 
755   bool fSubtractFeeFromAmount = false;
756   if (!request.params[4].isNull())
757       fSubtractFeeFromAmount = request.params[4].get_bool();
758 
759   CCoinControl coin_control;
760   if (!request.params[5].isNull()) {
761       coin_control.m_signal_bip125_rbf = request.params[5].get_bool();
762   }
763 
764   EnsureWalletIsUnlocked(pwallet);
765 
766   std::vector<CRecipient> recipients;
767   const CAmount amount = AmountFromValue (request.params[1]);
768   recipients.push_back ({data.getAddress (), amount, fSubtractFeeFromAmount});
769 
770   return SendMoney(pwallet, coin_control, nullptr, recipients, mapValue, false);
771 }
772   };
773 }
774