1 // Copyright (c) 2014-2020 Daniel Kraft
2 // Copyright (c) 2020 yanmaani
3 // Distributed under the MIT/X11 software license, see the accompanying
4 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
5 
6 #include <base58.h>
7 #include <chainparams.h>
8 #include <core_io.h>
9 #include <init.h>
10 #include <index/namehash.h>
11 #include <key_io.h>
12 #include <names/common.h>
13 #include <names/main.h>
14 #include <node/context.h>
15 #include <primitives/transaction.h>
16 #include <psbt.h>
17 #include <rpc/blockchain.h>
18 #include <rpc/names.h>
19 #include <rpc/server.h>
20 #include <script/names.h>
21 #include <txmempool.h>
22 #include <util/strencodings.h>
23 #include <validation.h>
24 #ifdef ENABLE_WALLET
25 # include <wallet/rpcwallet.h>
26 # include <wallet/wallet.h>
27 #endif
28 
29 #include <univalue.h>
30 
31 #include <boost/xpressive/xpressive_dynamic.hpp>
32 
33 #include <algorithm>
34 #include <cassert>
35 #include <memory>
36 #include <stdexcept>
37 
38 namespace
39 {
40 
41 NameEncoding
EncodingFromOptionsJson(const UniValue & options,const std::string & field,const NameEncoding defaultValue)42 EncodingFromOptionsJson (const UniValue& options, const std::string& field,
43                          const NameEncoding defaultValue)
44 {
45   NameEncoding res = defaultValue;
46   RPCTypeCheckObj (options,
47     {
48       {field, UniValueType (UniValue::VSTR)},
49     },
50     true, false);
51   if (options.exists (field))
52     try
53       {
54         res = EncodingFromString (options[field].get_str ());
55       }
56     catch (const std::invalid_argument& exc)
57       {
58         LogPrintf ("Invalid value for %s in options: %s\n  using default %s\n",
59                    field, exc.what (), EncodingToString (defaultValue));
60       }
61 
62   return res;
63 }
64 
65 } // anonymous namespace
66 
67 /**
68  * Utility routine to construct a "name info" object to return.  This is used
69  * for name_show and also name_list.
70  */
71 UniValue
getNameInfo(const UniValue & options,const valtype & name,const valtype & value,const COutPoint & outp,const CScript & addr)72 getNameInfo (const UniValue& options,
73              const valtype& name, const valtype& value,
74              const COutPoint& outp, const CScript& addr)
75 {
76   UniValue obj(UniValue::VOBJ);
77   AddEncodedNameToUniv (obj, "name", name,
78                         EncodingFromOptionsJson (options, "nameEncoding",
79                                                  ConfiguredNameEncoding ()));
80   AddEncodedNameToUniv (obj, "value", value,
81                         EncodingFromOptionsJson (options, "valueEncoding",
82                                                  ConfiguredValueEncoding ()));
83   obj.pushKV ("txid", outp.hash.GetHex ());
84   obj.pushKV ("vout", static_cast<int> (outp.n));
85 
86   /* Try to extract the address.  May fail if we can't parse the script
87      as a "standard" script.  */
88   CTxDestination dest;
89   std::string addrStr;
90   if (ExtractDestination (addr, dest))
91     addrStr = EncodeDestination (dest);
92   else
93     addrStr = "<nonstandard>";
94   obj.pushKV ("address", addrStr);
95 
96   return obj;
97 }
98 
99 /**
100  * Return name info object for a CNameData object.
101  */
102 UniValue
getNameInfo(const UniValue & options,const valtype & name,const CNameData & data)103 getNameInfo (const UniValue& options,
104              const valtype& name, const CNameData& data)
105 {
106   UniValue result = getNameInfo (options,
107                                  name, data.getValue (),
108                                  data.getUpdateOutpoint (),
109                                  data.getAddress ());
110   addExpirationInfo (data.getHeight (), result);
111   return result;
112 }
113 
114 /**
115  * Adds expiration information to the JSON object, based on the last-update
116  * height for the name given.
117  */
118 void
addExpirationInfo(const int height,UniValue & data)119 addExpirationInfo (const int height, UniValue& data)
120 {
121   const int curHeight = ::ChainActive ().Height ();
122   const Consensus::Params& params = Params ().GetConsensus ();
123   const int expireDepth = params.rules->NameExpirationDepth (curHeight);
124   const int expireHeight = height + expireDepth;
125   const int expiresIn = expireHeight - curHeight;
126   const bool expired = (expiresIn <= 0);
127   data.pushKV ("height", height);
128   data.pushKV ("expires_in", expiresIn);
129   data.pushKV ("expired", expired);
130 }
131 
132 #ifdef ENABLE_WALLET
133 /**
134  * Adds the "ismine" field giving ownership info to the JSON object.
135  */
136 void
addOwnershipInfo(const CScript & addr,const CWallet * pwallet,UniValue & data)137 addOwnershipInfo (const CScript& addr, const CWallet* pwallet,
138                   UniValue& data)
139 {
140   if (pwallet == nullptr)
141     return;
142 
143   AssertLockHeld (pwallet->cs_wallet);
144   const isminetype mine = pwallet->IsMine (addr);
145   const bool isMine = (mine & ISMINE_SPENDABLE);
146   data.pushKV ("ismine", isMine);
147 }
148 #endif
149 
150 namespace
151 {
152 
153 valtype
DecodeNameValueFromRPCOrThrow(const UniValue & val,const UniValue & opt,const std::string & optKey,const NameEncoding defaultEnc)154 DecodeNameValueFromRPCOrThrow (const UniValue& val, const UniValue& opt,
155                                const std::string& optKey,
156                                const NameEncoding defaultEnc)
157 {
158   const NameEncoding enc = EncodingFromOptionsJson (opt, optKey, defaultEnc);
159   try
160     {
161       return DecodeName (val.get_str (), enc);
162     }
163   catch (const InvalidNameString& exc)
164     {
165       std::ostringstream msg;
166       msg << "Name/value is invalid for encoding " << EncodingToString (enc);
167       throw JSONRPCError (RPC_NAME_INVALID_ENCODING, msg.str ());
168     }
169 }
170 
171 } // anonymous namespace
172 
173 valtype
DecodeNameFromRPCOrThrow(const UniValue & val,const UniValue & opt)174 DecodeNameFromRPCOrThrow (const UniValue& val, const UniValue& opt)
175 {
176   return DecodeNameValueFromRPCOrThrow (val, opt, "nameEncoding",
177                                         ConfiguredNameEncoding ());
178 }
179 
180 valtype
DecodeValueFromRPCOrThrow(const UniValue & val,const UniValue & opt)181 DecodeValueFromRPCOrThrow (const UniValue& val, const UniValue& opt)
182 {
183   return DecodeNameValueFromRPCOrThrow (val, opt, "valueEncoding",
184                                         ConfiguredValueEncoding ());
185 }
186 
187 namespace
188 {
189 
190 /**
191  * Decodes the identifier for a name lookup according to the nameEncoding,
192  * and also looks up the preimage if we look up by hash.
193  */
194 valtype
GetNameForLookup(const UniValue & val,const UniValue & opt)195 GetNameForLookup (const UniValue& val, const UniValue& opt)
196 {
197   const valtype identifier = DecodeNameFromRPCOrThrow (val, opt);
198 
199   RPCTypeCheckObj (opt,
200     {
201       {"byHash", UniValueType (UniValue::VSTR)},
202     },
203     true, false);
204 
205   if (!opt.exists ("byHash"))
206     return identifier;
207 
208   const std::string byHashType = opt["byHash"].get_str ();
209   if (byHashType == "direct")
210     return identifier;
211 
212   if (g_name_hash_index == nullptr)
213     throw std::runtime_error ("-namehashindex is not enabled");
214   if (!g_name_hash_index->BlockUntilSyncedToCurrentChain ())
215     throw std::runtime_error ("The name-hash index is not caught up yet");
216 
217   if (byHashType != "sha256d")
218     {
219       std::ostringstream msg;
220       msg << "Invalid value for byHash: " << byHashType;
221       throw JSONRPCError (RPC_INVALID_PARAMETER, msg.str ());
222     }
223 
224   if (identifier.size () != 32)
225     throw JSONRPCError (RPC_INVALID_PARAMETER,
226                         "SHA-256d hash must be 32 bytes long");
227 
228   const uint256 hash(identifier);
229   valtype name;
230   if (!g_name_hash_index->FindNamePreimage (hash, name))
231     {
232       std::ostringstream msg;
233       msg << "name hash not found: " << hash.GetHex ();
234       throw JSONRPCError (RPC_WALLET_ERROR, msg.str ());
235     }
236 
237   return name;
238 }
239 
240 /**
241  * Helper class that extracts the wallet for the current RPC request, if any.
242  * It handles the case of disabled wallet support or no wallet being present,
243  * so that it is suitable for the non-wallet RPCs here where we just want to
244  * provide optional extra features (like the "ismine" field).
245  *
246  * The main benefit of having this class is that we can easily LOCK2 with the
247  * wallet and another lock we need, without having to care about the special
248  * cases where no wallet is present or wallet support is disabled.
249  */
250 class MaybeWalletForRequest
251 {
252 
253 private:
254 
255 #ifdef ENABLE_WALLET
256   std::shared_ptr<CWallet> wallet;
257 #endif
258 
259 public:
260 
MaybeWalletForRequest(const JSONRPCRequest & request)261   explicit MaybeWalletForRequest (const JSONRPCRequest& request)
262   {
263 #ifdef ENABLE_WALLET
264     try
265       {
266         wallet = GetWalletForJSONRPCRequest (request);
267       }
268     catch (const UniValue& exc)
269       {
270         const auto& code = exc["code"];
271         if (!code.isNum () || code.get_int () != RPC_WALLET_NOT_SPECIFIED)
272           throw;
273 
274         /* If the wallet is not set, that's fine, and we just indicate it to
275            other code (by having a null wallet).  */
276         wallet = nullptr;
277       }
278 #endif
279   }
280 
281   RecursiveMutex*
getLock() const282   getLock () const
283   {
284 #ifdef ENABLE_WALLET
285     return (wallet != nullptr ? &wallet->cs_wallet : nullptr);
286 #else
287     return nullptr;
288 #endif
289   }
290 
291 #ifdef ENABLE_WALLET
292   CWallet*
getWallet()293   getWallet ()
294   {
295     return wallet.get ();
296   }
297 
298   const CWallet*
getWallet() const299   getWallet () const
300   {
301     return wallet.get ();
302   }
303 #endif
304 
305 };
306 
307 /**
308  * Variant of addOwnershipInfo that uses a MaybeWalletForRequest.  This takes
309  * care of disabled wallet support.
310  */
311 void
addOwnershipInfo(const CScript & addr,const MaybeWalletForRequest & wallet,UniValue & data)312 addOwnershipInfo (const CScript& addr, const MaybeWalletForRequest& wallet,
313                   UniValue& data)
314 {
315 #ifdef ENABLE_WALLET
316   addOwnershipInfo (addr, wallet.getWallet (), data);
317 #endif
318 }
319 
320 /**
321  * Utility variant of getNameInfo that already includes ownership information.
322  * This is the most common call for methods in this file.
323  */
324 UniValue
getNameInfo(const UniValue & options,const valtype & name,const CNameData & data,const MaybeWalletForRequest & wallet)325 getNameInfo (const UniValue& options,
326              const valtype& name, const CNameData& data,
327              const MaybeWalletForRequest& wallet)
328 {
329   UniValue res = getNameInfo (options, name, data);
330   addOwnershipInfo (data.getAddress (), wallet, res);
331   return res;
332 }
333 
334 } // anonymous namespace
335 
336 /* ************************************************************************** */
337 
NameInfoHelp()338 NameInfoHelp::NameInfoHelp ()
339 {
340   withField ({RPCResult::Type::STR, "name", "the requested name"});
341   withField ({RPCResult::Type::STR, "name_encoding", "the encoding of \"name\""});
342   withField ({RPCResult::Type::STR, "name_error",
343               "replaces \"name\" in case there is an error"});
344   withField ({RPCResult::Type::STR, "value", "the name's current value"});
345   withField ({RPCResult::Type::STR, "value_encoding", "the encoding of \"value\""});
346   withField ({RPCResult::Type::STR, "value_error",
347               "replaces \"value\" in case there is an error"});
348 
349   withField ({RPCResult::Type::STR_HEX, "txid", "the name's last update tx"});
350   withField ({RPCResult::Type::NUM, "vout",
351               "the index of the name output in the last update"});
352   withField ({RPCResult::Type::STR, "address", "the address holding the name"});
353 #ifdef ENABLE_WALLET
354   withField ({RPCResult::Type::BOOL, "ismine",
355               "whether the name is owned by the wallet"});
356 #endif
357 }
358 
359 NameInfoHelp&
withExpiration()360 NameInfoHelp::withExpiration ()
361 {
362   withField ({RPCResult::Type::NUM, "height", "the name's last update height"});
363   withField ({RPCResult::Type::NUM, "expires_in", "expire counter for the name"});
364   withField ({RPCResult::Type::BOOL, "expired", "whether the name is expired"});
365   return *this;
366 }
367 
NameOptionsHelp()368 NameOptionsHelp::NameOptionsHelp ()
369 {}
370 
371 NameOptionsHelp&
withArg(const std::string & name,const RPCArg::Type type,const std::string & doc)372 NameOptionsHelp::withArg (const std::string& name, const RPCArg::Type type,
373                           const std::string& doc)
374 {
375   return withArg (name, type, "", doc);
376 }
377 
378 NameOptionsHelp&
withArg(const std::string & name,const RPCArg::Type type,const std::string & defaultValue,const std::string & doc)379 NameOptionsHelp::withArg (const std::string& name, const RPCArg::Type type,
380                           const std::string& defaultValue,
381                           const std::string& doc)
382 {
383   if (defaultValue.empty ())
384     innerArgs.push_back (RPCArg (name, type, RPCArg::Optional::OMITTED, doc));
385   else
386     innerArgs.push_back (RPCArg (name, type, defaultValue, doc));
387 
388   return *this;
389 }
390 
391 NameOptionsHelp&
withWriteOptions()392 NameOptionsHelp::withWriteOptions ()
393 {
394   withArg ("destAddress", RPCArg::Type::STR,
395            "The address to send the name output to");
396 
397   withArg ("sendCoins", RPCArg::Type::OBJ_USER_KEYS,
398            "Addresses to which coins should be sent additionally");
399 
400   return *this;
401 }
402 
403 NameOptionsHelp&
withNameEncoding()404 NameOptionsHelp::withNameEncoding ()
405 {
406   withArg ("nameEncoding", RPCArg::Type::STR,
407            "Encoding (\"ascii\", \"utf8\" or \"hex\") of the name argument");
408   return *this;
409 }
410 
411 NameOptionsHelp&
withValueEncoding()412 NameOptionsHelp::withValueEncoding ()
413 {
414   withArg ("valueEncoding", RPCArg::Type::STR,
415            "Encoding (\"ascii\", \"utf8\" or \"hex\") of the value argument");
416   return *this;
417 }
418 
419 NameOptionsHelp&
withByHash()420 NameOptionsHelp::withByHash ()
421 {
422   withArg ("byHash", RPCArg::Type::STR,
423            "Interpret \"name\" as hash (\"direct\" or \"sha256d\")");
424   return *this;
425 }
426 
427 RPCArg
buildRpcArg() const428 NameOptionsHelp::buildRpcArg () const
429 {
430   return RPCArg ("options", RPCArg::Type::OBJ,
431                  RPCArg::Optional::OMITTED_NAMED_ARG,
432                  "Options for this RPC call",
433                  innerArgs, "options");
434 }
435 
436 /* ************************************************************************** */
437 namespace
438 {
439 
440 RPCHelpMan
name_show()441 name_show ()
442 {
443   const bool allow_expired_default = gArgs.GetBoolArg("-allowexpired", DEFAULT_ALLOWEXPIRED);
444 
445   NameOptionsHelp optHelp;
446   optHelp
447       .withNameEncoding ()
448       .withValueEncoding ()
449       .withByHash ()
450       .withArg ("allowExpired", RPCArg::Type::BOOL, allow_expired_default ? "true" : "false",
451                 "Whether to throw error for expired names");
452 
453   return RPCHelpMan ("name_show",
454       "\nLooks up the current data for the given name.  Fails if the name doesn't exist.\n",
455       {
456           {"name", RPCArg::Type::STR, RPCArg::Optional::NO, "The name to query for"},
457           optHelp.buildRpcArg (),
458       },
459       NameInfoHelp ()
460         .withExpiration ()
461         .finish (),
462       RPCExamples {
463           HelpExampleCli ("name_show", "\"myname\"")
464         + HelpExampleCli ("name_show", R"("myname" '{"allowExpired": false}')")
465         + HelpExampleRpc ("name_show", "\"myname\"")
466       },
467       [&] (const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
468 {
469   RPCTypeCheck (request.params, {UniValue::VSTR, UniValue::VOBJ});
470 
471   if (::ChainstateActive ().IsInitialBlockDownload ())
472     throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD,
473                        "Namecoin is downloading blocks...");
474 
475   UniValue options(UniValue::VOBJ);
476   if (request.params.size () >= 2)
477     options = request.params[1].get_obj ();
478 
479   /* Parse and interpret the name_show-specific options.  */
480   RPCTypeCheckObj(options,
481     {
482       {"allowExpired", UniValueType(UniValue::VBOOL)},
483     },
484     true, false);
485 
486   bool allow_expired = allow_expired_default;
487   if (options.exists("allowExpired"))
488     allow_expired = options["allowExpired"].get_bool();
489 
490   const valtype name = GetNameForLookup (request.params[0], options);
491 
492   CNameData data;
493   {
494     LOCK (cs_main);
495     if (!::ChainstateActive ().CoinsTip ().GetName (name, data))
496       {
497         std::ostringstream msg;
498         msg << "name not found: " << EncodeNameForMessage (name);
499         throw JSONRPCError (RPC_WALLET_ERROR, msg.str ());
500       }
501   }
502 
503   MaybeWalletForRequest wallet(request);
504   LOCK2 (wallet.getLock (), cs_main);
505   UniValue name_object = getNameInfo(options, name, data, wallet);
506   assert(!name_object["expired"].isNull());
507   const bool is_expired = name_object["expired"].get_bool();
508   if (is_expired && !allow_expired)
509     {
510       std::ostringstream msg;
511       msg << "name not found: " << EncodeNameForMessage(name);
512       throw JSONRPCError(RPC_WALLET_ERROR, msg.str());
513     }
514   return name_object;
515 }
516   );
517 }
518 
519 /* ************************************************************************** */
520 
521 RPCHelpMan
name_history()522 name_history ()
523 {
524   NameOptionsHelp optHelp;
525   optHelp
526       .withNameEncoding ()
527       .withValueEncoding ()
528       .withByHash ();
529 
530   return RPCHelpMan ("name_history",
531       "\nLooks up the current and all past data for the given name.  -namehistory must be enabled.\n",
532       {
533           {"name", RPCArg::Type::STR, RPCArg::Optional::NO, "The name to query for"},
534           optHelp.buildRpcArg (),
535       },
536       RPCResult {RPCResult::Type::ARR, "", "",
537           {
538               NameInfoHelp ()
539                 .withExpiration ()
540                 .finish ()
541           }
542       },
543       RPCExamples {
544           HelpExampleCli ("name_history", "\"myname\"")
545         + HelpExampleRpc ("name_history", "\"myname\"")
546       },
547       [&] (const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
548 {
549   RPCTypeCheck (request.params, {UniValue::VSTR, UniValue::VOBJ});
550 
551   if (!fNameHistory)
552     throw std::runtime_error ("-namehistory is not enabled");
553 
554   if (::ChainstateActive ().IsInitialBlockDownload ())
555     throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD,
556                        "Namecoin is downloading blocks...");
557 
558   UniValue options(UniValue::VOBJ);
559   if (request.params.size () >= 2)
560     options = request.params[1].get_obj ();
561 
562   const valtype name = GetNameForLookup (request.params[0], options);
563 
564   CNameData data;
565   CNameHistory history;
566 
567   {
568     LOCK (cs_main);
569 
570     const auto& coinsTip = ::ChainstateActive ().CoinsTip ();
571     if (!coinsTip.GetName (name, data))
572       {
573         std::ostringstream msg;
574         msg << "name not found: " << EncodeNameForMessage (name);
575         throw JSONRPCError (RPC_WALLET_ERROR, msg.str ());
576       }
577 
578     if (!coinsTip.GetNameHistory (name, history))
579       assert (history.empty ());
580   }
581 
582   MaybeWalletForRequest wallet(request);
583   LOCK2 (wallet.getLock (), cs_main);
584 
585   UniValue res(UniValue::VARR);
586   for (const auto& entry : history.getData ())
587     res.push_back (getNameInfo (options, name, entry, wallet));
588   res.push_back (getNameInfo (options, name, data, wallet));
589 
590   return res;
591 }
592   );
593 }
594 
595 /* ************************************************************************** */
596 
597 RPCHelpMan
name_scan()598 name_scan ()
599 {
600   NameOptionsHelp optHelp;
601   optHelp
602       .withNameEncoding ()
603       .withValueEncoding ()
604       .withArg ("minConf", RPCArg::Type::NUM, "1",
605                 "Minimum number of confirmations")
606       .withArg ("maxConf", RPCArg::Type::NUM,
607                 "Maximum number of confirmations")
608       .withArg ("prefix", RPCArg::Type::STR,
609                 "Filter for names with the given prefix")
610       .withArg ("regexp", RPCArg::Type::STR,
611                 "Filter for names matching the regexp");
612 
613   return RPCHelpMan ("name_scan",
614       "\nLists names in the database.\n",
615       {
616           {"start", RPCArg::Type::STR, "", "Skip initially to this name"},
617           {"count", RPCArg::Type::NUM, "500", "Stop after this many names"},
618           optHelp.buildRpcArg (),
619       },
620       RPCResult {RPCResult::Type::ARR, "", "",
621           {
622               NameInfoHelp ()
623                 .withExpiration ()
624                 .finish ()
625           }
626       },
627       RPCExamples {
628           HelpExampleCli ("name_scan", "")
629         + HelpExampleCli ("name_scan", "\"d/abc\"")
630         + HelpExampleCli ("name_scan", "\"d/abc\" 10")
631         + HelpExampleRpc ("name_scan", "\"d/abc\"")
632       },
633       [&] (const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
634 {
635   RPCTypeCheck (request.params,
636                 {UniValue::VSTR, UniValue::VNUM, UniValue::VOBJ});
637 
638   if (::ChainstateActive ().IsInitialBlockDownload ())
639     throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD,
640                        "Namecoin is downloading blocks...");
641 
642   UniValue options(UniValue::VOBJ);
643   if (request.params.size () >= 3)
644     options = request.params[2].get_obj ();
645 
646   valtype start;
647   if (request.params.size () >= 1)
648     start = DecodeNameFromRPCOrThrow (request.params[0], options);
649 
650   int count = 500;
651   if (request.params.size () >= 2)
652     count = request.params[1].get_int ();
653 
654   /* Parse and interpret the name_scan-specific options.  */
655   RPCTypeCheckObj (options,
656     {
657       {"minConf", UniValueType (UniValue::VNUM)},
658       {"maxConf", UniValueType (UniValue::VNUM)},
659       {"prefix", UniValueType (UniValue::VSTR)},
660       {"regexp", UniValueType (UniValue::VSTR)},
661     },
662     true, false);
663 
664   int minConf = 1;
665   if (options.exists ("minConf"))
666     minConf = options["minConf"].get_int ();
667   if (minConf < 1)
668     throw JSONRPCError (RPC_INVALID_PARAMETER, "minConf must be >= 1");
669 
670   int maxConf = -1;
671   if (options.exists ("maxConf"))
672     {
673       maxConf = options["maxConf"].get_int ();
674       if (maxConf < 0)
675         throw JSONRPCError (RPC_INVALID_PARAMETER,
676                             "maxConf must not be negative");
677     }
678 
679   valtype prefix;
680   if (options.exists ("prefix"))
681     prefix = DecodeNameFromRPCOrThrow (options["prefix"], options);
682 
683   bool haveRegexp = false;
684   boost::xpressive::sregex regexp;
685   if (options.exists ("regexp"))
686     {
687       haveRegexp = true;
688       regexp = boost::xpressive::sregex::compile (options["regexp"].get_str ());
689     }
690 
691   /* Iterate over names and produce the result.  */
692   UniValue res(UniValue::VARR);
693   if (count <= 0)
694     return res;
695 
696   MaybeWalletForRequest wallet(request);
697   LOCK2 (wallet.getLock (), cs_main);
698 
699   const int maxHeight = ::ChainActive ().Height () - minConf + 1;
700   int minHeight = -1;
701   if (maxConf >= 0)
702     minHeight = ::ChainActive ().Height () - maxConf + 1;
703 
704   valtype name;
705   CNameData data;
706   const auto& coinsTip = ::ChainstateActive ().CoinsTip ();
707   std::unique_ptr<CNameIterator> iter(coinsTip.IterateNames ());
708   for (iter->seek (start); count > 0 && iter->next (name, data); )
709     {
710       const int height = data.getHeight ();
711       if (height > maxHeight)
712         continue;
713       if (minHeight >= 0 && height < minHeight)
714         continue;
715 
716       if (name.size () < prefix.size ())
717         continue;
718       if (!std::equal (prefix.begin (), prefix.end (), name.begin ()))
719         continue;
720 
721       if (haveRegexp)
722         {
723           try
724             {
725               const std::string nameStr = EncodeName (name, NameEncoding::UTF8);
726               boost::xpressive::smatch matches;
727               if (!boost::xpressive::regex_search (nameStr, matches, regexp))
728                 continue;
729             }
730           catch (const InvalidNameString& exc)
731             {
732               continue;
733             }
734         }
735 
736       res.push_back (getNameInfo (options, name, data, wallet));
737       --count;
738     }
739 
740   return res;
741 }
742   );
743 }
744 
745 /* ************************************************************************** */
746 
747 RPCHelpMan
name_pending()748 name_pending ()
749 {
750   NameOptionsHelp optHelp;
751   optHelp
752       .withNameEncoding ()
753       .withValueEncoding ();
754 
755   return RPCHelpMan ("name_pending",
756       "\nLists unconfirmed name operations in the mempool.\n"
757       "\nIf a name is given, only check for operations on this name.\n",
758       {
759           {"name", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, "Only look for this name"},
760           optHelp.buildRpcArg (),
761       },
762       RPCResult {RPCResult::Type::ARR, "", "",
763           {
764               NameInfoHelp ()
765                 .withField ({RPCResult::Type::STR, "op", "the operation being performed"})
766                 .withExpiration ()
767                 .finish ()
768           }
769       },
770       RPCExamples {
771           HelpExampleCli ("name_pending", "")
772         + HelpExampleCli ("name_pending", "\"d/domob\"")
773         + HelpExampleRpc ("name_pending", "")
774       },
775       [&] (const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
776 {
777   RPCTypeCheck (request.params, {UniValue::VSTR, UniValue::VOBJ}, true);
778 
779   MaybeWalletForRequest wallet(request);
780   auto& mempool = EnsureMemPool (request.context);
781   LOCK2 (wallet.getLock (), mempool.cs);
782 
783   UniValue options(UniValue::VOBJ);
784   if (request.params.size () >= 2)
785     options = request.params[1].get_obj ();
786 
787   std::vector<uint256> txHashes;
788   mempool.queryHashes (txHashes);
789 
790   const bool hasNameFilter = !request.params[0].isNull ();
791   valtype nameFilter;
792   if (hasNameFilter)
793     nameFilter = DecodeNameFromRPCOrThrow (request.params[0], options);
794 
795   UniValue arr(UniValue::VARR);
796   for (const auto& txHash : txHashes)
797     {
798       std::shared_ptr<const CTransaction> tx = mempool.get (txHash);
799       if (!tx || !tx->IsNamecoin ())
800         continue;
801 
802       for (size_t n = 0; n < tx->vout.size (); ++n)
803         {
804           const auto& txOut = tx->vout[n];
805           const CNameScript op(txOut.scriptPubKey);
806           if (!op.isNameOp () || !op.isAnyUpdate ())
807             continue;
808           if (hasNameFilter && op.getOpName () != nameFilter)
809             continue;
810 
811           UniValue obj = getNameInfo (options,
812                                       op.getOpName (), op.getOpValue (),
813                                       COutPoint (tx->GetHash (), n),
814                                       op.getAddress ());
815           addOwnershipInfo (op.getAddress (), wallet, obj);
816           switch (op.getNameOp ())
817             {
818             case OP_NAME_FIRSTUPDATE:
819               obj.pushKV ("op", "name_firstupdate");
820               break;
821             case OP_NAME_UPDATE:
822               obj.pushKV ("op", "name_update");
823               break;
824             default:
825               assert (false);
826             }
827 
828           arr.push_back (obj);
829         }
830     }
831 
832   return arr;
833 }
834   );
835 }
836 
837 /* ************************************************************************** */
838 
839 namespace
840 {
841 
842 /**
843  * Performs the action of namerawtransaction and namepsbt on a given
844  * CMutableTransaction.  This is used to share the code between the two
845  * RPC methods.
846  *
847  * If a name_new is created and a rand value chosen, it will be placed
848  * into the JSON output "result" already.
849  */
850 void
PerformNameRawtx(const int nOut,const UniValue & nameOp,CMutableTransaction & mtx,UniValue & result)851 PerformNameRawtx (const int nOut, const UniValue& nameOp,
852                   CMutableTransaction& mtx, UniValue& result)
853 {
854   mtx.SetNamecoin ();
855 
856   if (nOut < 0 || nOut >= mtx.vout.size ())
857     throw JSONRPCError (RPC_INVALID_PARAMETER, "vout is out of range");
858   auto& script = mtx.vout[nOut].scriptPubKey;
859 
860   RPCTypeCheckObj (nameOp,
861     {
862       {"op", UniValueType (UniValue::VSTR)},
863     }
864   );
865   const std::string op = find_value (nameOp, "op").get_str ();
866 
867   /* namerawtransaction does not have an options argument.  This would just
868      make the already long list of arguments longer.  Instead of using
869      namerawtransaction, namecoin-tx can be used anyway to create name
870      operations with arbitrary hex data.  */
871   const UniValue NO_OPTIONS(UniValue::VOBJ);
872 
873   if (op == "name_new")
874     {
875       RPCTypeCheckObj (nameOp,
876         {
877           {"name", UniValueType (UniValue::VSTR)},
878           {"rand", UniValueType (UniValue::VSTR)},
879         },
880         true);
881 
882       valtype rand;
883       if (nameOp.exists ("rand"))
884         {
885           const std::string randStr = find_value (nameOp, "rand").get_str ();
886           if (!IsHex (randStr))
887             throw JSONRPCError (RPC_DESERIALIZATION_ERROR, "rand must be hex");
888           rand = ParseHex (randStr);
889         }
890       else
891         {
892           rand.resize (20);
893           GetRandBytes (&rand[0], rand.size ());
894         }
895 
896       const valtype name
897           = DecodeNameFromRPCOrThrow (find_value (nameOp, "name"), NO_OPTIONS);
898 
899       script = CNameScript::buildNameNew (script, name, rand);
900       result.pushKV ("rand", HexStr (rand));
901     }
902   else if (op == "name_firstupdate")
903     {
904       RPCTypeCheckObj (nameOp,
905         {
906           {"name", UniValueType (UniValue::VSTR)},
907           {"value", UniValueType (UniValue::VSTR)},
908           {"rand", UniValueType (UniValue::VSTR)},
909         }
910       );
911 
912       const std::string randStr = find_value (nameOp, "rand").get_str ();
913       if (!IsHex (randStr))
914         throw JSONRPCError (RPC_DESERIALIZATION_ERROR, "rand must be hex");
915       const valtype rand = ParseHex (randStr);
916 
917       const valtype name
918           = DecodeNameFromRPCOrThrow (find_value (nameOp, "name"), NO_OPTIONS);
919       const valtype value
920           = DecodeValueFromRPCOrThrow (find_value (nameOp, "value"),
921                                        NO_OPTIONS);
922 
923       script = CNameScript::buildNameFirstupdate (script, name, value, rand);
924     }
925   else if (op == "name_update")
926     {
927       RPCTypeCheckObj (nameOp,
928         {
929           {"name", UniValueType (UniValue::VSTR)},
930           {"value", UniValueType (UniValue::VSTR)},
931         }
932       );
933 
934       const valtype name
935           = DecodeNameFromRPCOrThrow (find_value (nameOp, "name"), NO_OPTIONS);
936       const valtype value
937           = DecodeValueFromRPCOrThrow (find_value (nameOp, "value"),
938                                        NO_OPTIONS);
939 
940       script = CNameScript::buildNameUpdate (script, name, value);
941     }
942   else
943     throw JSONRPCError (RPC_INVALID_PARAMETER, "Invalid name operation");
944 }
945 
946 } // anonymous namespace
947 
948 RPCHelpMan
namerawtransaction()949 namerawtransaction ()
950 {
951   return RPCHelpMan ("namerawtransaction",
952       "\nAdds a name operation to an existing raw transaction.\n"
953       "\nUse createrawtransaction first to create the basic transaction, including the required inputs and outputs also for the name.\n",
954       {
955           {"hexstring", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction hex string"},
956           {"vout", RPCArg::Type::NUM, RPCArg::Optional::NO, "The vout of the desired name output"},
957           {"nameop", RPCArg::Type::OBJ, RPCArg::Optional::NO, "The name operation to create",
958               {
959                   {"op", RPCArg::Type::STR, RPCArg::Optional::NO, "The operation to perform, can be \"name_new\", \"name_firstupdate\" and \"name_update\""},
960                   {"name", RPCArg::Type::STR, RPCArg::Optional::NO, "The name to operate on"},
961                   {"value", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "The new value for the name"},
962                   {"rand", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "The nonce value to use for registrations"},
963               },
964            "nameop"},
965       },
966       RPCResult {RPCResult::Type::OBJ, "", "",
967           {
968               {RPCResult::Type::STR_HEX, "hex", "Hex string of the updated transaction"},
969               {RPCResult::Type::STR_HEX, "rand", /* optional */ true, "If this is a name_new, the nonce used to create it"},
970           },
971       },
972       RPCExamples {
973           HelpExampleCli ("namerawtransaction", R"("raw tx hex" 1 "{\"op\":\"name_new\",\"name\":\"my-name\")")
974         + HelpExampleCli ("namerawtransaction", R"("raw tx hex" 1 "{\"op\":\"name_firstupdate\",\"name\":\"my-name\",\"value\":\"new value\",\"rand\":\"00112233\")")
975         + HelpExampleCli ("namerawtransaction", R"("raw tx hex" 1 "{\"op\":\"name_update\",\"name\":\"my-name\",\"value\":\"new value\")")
976         + HelpExampleRpc ("namerawtransaction", R"("raw tx hex", 1, "{\"op\":\"name_update\",\"name\":\"my-name\",\"value\":\"new value\")")
977       },
978       [&] (const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
979 {
980   RPCTypeCheck (request.params,
981                 {UniValue::VSTR, UniValue::VNUM, UniValue::VOBJ});
982 
983   CMutableTransaction mtx;
984   if (!DecodeHexTx (mtx, request.params[0].get_str (), true))
985     throw JSONRPCError (RPC_DESERIALIZATION_ERROR, "TX decode failed");
986 
987   UniValue result(UniValue::VOBJ);
988 
989   PerformNameRawtx (request.params[1].get_int (), request.params[2].get_obj (),
990                     mtx, result);
991 
992   result.pushKV ("hex", EncodeHexTx (CTransaction (mtx)));
993   return result;
994 }
995   );
996 }
997 
998 RPCHelpMan
999 namepsbt ()
1000 {
1001   return RPCHelpMan ("namepsbt",
1002       "\nAdds a name operation to an existing PSBT.\n"
1003       "\nUse createpsbt first to create the basic transaction, including the required inputs and outputs also for the name.\n",
1004       {
1005           {"psbt", RPCArg::Type::STR, RPCArg::Optional::NO, "A base64 string of a PSBT"},
1006           {"vout", RPCArg::Type::NUM, RPCArg::Optional::NO, "The vout of the desired name output"},
1007           {"nameop", RPCArg::Type::OBJ, RPCArg::Optional::NO, "The name operation to create",
1008               {
1009                   {"op", RPCArg::Type::STR, RPCArg::Optional::NO, "The operation to perform, can be \"name_new\", \"name_firstupdate\" and \"name_update\""},
1010                   {"name", RPCArg::Type::STR, RPCArg::Optional::NO, "The name to operate on"},
1011                   {"value", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "The new value for the name"},
1012                   {"rand", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "The nonce value to use for registrations"},
1013               },
1014            "nameop"},
1015       },
1016       RPCResult {RPCResult::Type::OBJ, "", "",
1017           {
1018               {RPCResult::Type::STR_HEX, "psbt", "The serialised, updated PSBT"},
1019               {RPCResult::Type::STR_HEX, "rand", /* optional */ true, "If this is a name_new, the nonce used to create it"},
1020           },
1021       },
1022       RPCExamples {
1023           HelpExampleCli ("namepsbt", R"("psbt" 1 "{\"op\":\"name_new\",\"name\":\"my-name\")")
1024         + HelpExampleCli ("namepsbt", R"("psbt" 1 "{\"op\":\"name_firstupdate\",\"name\":\"my-name\",\"value\":\"new value\",\"rand\":\"00112233\")")
1025         + HelpExampleCli ("namepsbt", R"("psbt" 1 "{\"op\":\"name_update\",\"name\":\"my-name\",\"value\":\"new value\")")
1026         + HelpExampleRpc ("namepsbt", R"("psbt", 1, "{\"op\":\"name_update\",\"name\":\"my-name\",\"value\":\"new value\")")
1027       },
1028       [&] (const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
1029 {
1030   RPCTypeCheck (request.params,
1031                 {UniValue::VSTR, UniValue::VNUM, UniValue::VOBJ});
1032 
1033   PartiallySignedTransaction psbtx;
1034   std::string error;
1035   if (!DecodeBase64PSBT (psbtx, request.params[0].get_str (), error))
1036     throw JSONRPCError (RPC_DESERIALIZATION_ERROR,
1037                         strprintf ("TX decode failed %s", error));
1038 
1039   UniValue result(UniValue::VOBJ);
1040 
1041   PerformNameRawtx (request.params[1].get_int (), request.params[2].get_obj (),
1042                     *psbtx.tx, result);
1043 
1044   CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
1045   ssTx << psbtx;
1046   const auto* data = reinterpret_cast<const unsigned char*> (ssTx.data ());
1047   result.pushKV ("psbt", EncodeBase64 (MakeUCharSpan (ssTx)));
1048 
1049   return result;
1050 }
1051   );
1052 }
1053 
1054 /* ************************************************************************** */
1055 
1056 RPCHelpMan
1057 name_checkdb ()
1058 {
1059   return RPCHelpMan ("name_checkdb",
1060       "\nValidates the name DB's consistency.\n"
1061       "\nRoughly between blocks 139,000 and 180,000, this call is expected to fail due to the historic 'name stealing' bug.\n",
1062       {},
1063       RPCResult {RPCResult::Type::BOOL, "", "whether the state is valid"},
1064       RPCExamples {
1065           HelpExampleCli ("name_checkdb", "")
1066         + HelpExampleRpc ("name_checkdb", "")
1067       },
1068       [&] (const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
1069 {
1070   ChainstateManager& chainman = EnsureChainman (request.context);
1071   NodeContext& node = EnsureNodeContext (request.context);
1072 
1073   LOCK (cs_main);
1074   auto& coinsTip = chainman.ActiveChainstate ().CoinsTip ();
1075   coinsTip.Flush ();
1076   return coinsTip.ValidateNameDB (chainman, node.rpc_interruption_point);
1077 }
1078   );
1079 }
1080 
1081 } // namespace
1082 /* ************************************************************************** */
1083 
1084 void RegisterNameRPCCommands(CRPCTable &t)
1085 {
1086 static const CRPCCommand commands[] =
1087 { //  category              name                      actor (function)         argNames
1088   //  --------------------- ------------------------  -----------------------  ----------
1089     { "names",              "name_show",              &name_show,              {"name", "options"} },
1090     { "names",              "name_history",           &name_history,           {"name", "options"} },
1091     { "names",              "name_scan",              &name_scan,              {"start", "count", "options"} },
1092     { "names",              "name_pending",           &name_pending,           {"name", "options"} },
1093     { "names",              "name_checkdb",           &name_checkdb,           {} },
1094     { "rawtransactions",    "namerawtransaction",     &namerawtransaction,     {"hexstring", "vout", "nameop"} },
1095     { "rawtransactions",    "namepsbt",               &namepsbt,               {"psbt", "vout", "nameop"} },
1096 };
1097 
1098     for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++)
1099         t.appendCommand(commands[vcidx].name, &commands[vcidx]);
1100 }
1101