/** * Utility routine to construct a "name info" object to return. This is used * for name_show and also name_list. * @param name The name. * @param value The name's value. * @param outp The last update's outpoint. * @param addr The name's address script. * @param height The name's last update height. * @return A JSON object to return. */ UniValue getNameInfo (const valtype& name, const valtype& value, const COutPoint& outp, const CScript& addr, int height) { UniValue obj(UniValue::VOBJ); obj.push_back (Pair ("name", ValtypeToString (name))); obj.push_back (Pair ("value", ValtypeToString (value))); obj.push_back (Pair ("txid", outp.hash.GetHex ())); obj.push_back (Pair ("vout", static_cast<int> (outp.n))); /* Try to extract the address. May fail if we can't parse the script as a "standard" script. */ CTxDestination dest; CBitcoinAddress addrParsed; std::string addrStr; if (ExtractDestination (addr, dest) && addrParsed.Set (dest)) addrStr = addrParsed.ToString (); else addrStr = "<nonstandard>"; obj.push_back (Pair ("address", addrStr)); /* Calculate expiration data. */ const int curHeight = chainActive.Height (); const Consensus::Params& params = Params ().GetConsensus (); const int expireDepth = params.rules->NameExpirationDepth (curHeight); const int expireHeight = height + expireDepth; const int expiresIn = expireHeight - curHeight; const bool expired = (expiresIn <= 0); obj.push_back (Pair ("height", height)); obj.push_back (Pair ("expires_in", expiresIn)); obj.push_back (Pair ("expired", expired)); return obj; }
void refreshName(const std::vector<unsigned char> &inName) { LOCK(cs_main); NameTableEntry nameObj(ValtypeToString(inName), std::string(""), NameTableEntry::NAME_NON_EXISTING); CNameData data; { LOCK (cs_main); if (!pcoinsTip->GetName (inName, data)) { LogPrintf ("name not found: '%s'\n", ValtypeToString (inName).c_str()); return; } nameObj = NameTableEntry(ValtypeToString(inName), ValtypeToString(data.getValue ()), data.getHeight ()); } // Find name in model QList<NameTableEntry>::iterator lower = qLowerBound( cachedNameTable.begin(), cachedNameTable.end(), nameObj.name, NameTableEntryLessThan()); QList<NameTableEntry>::iterator upper = qUpperBound( cachedNameTable.begin(), cachedNameTable.end(), nameObj.name, NameTableEntryLessThan()); bool inModel = (lower != upper); if (inModel) { // In model - update or delete if (nameObj.nHeight != NameTableEntry::NAME_NON_EXISTING) { LogPrintf ("refreshName result : %s - refreshed in the table\n", qPrintable(nameObj.name)); updateEntry(nameObj.name, nameObj.value, nameObj.nHeight, CT_UPDATED); } else { LogPrintf("refreshName result : %s - deleted from the table\n", qPrintable(nameObj.name)); updateEntry(nameObj.name, nameObj.value, nameObj.nHeight, CT_DELETED); } } else { // Not in model - add or do nothing if (nameObj.nHeight != NameTableEntry::NAME_NON_EXISTING) { LogPrintf("refreshName result : %s - added to the table\n", qPrintable(nameObj.name)); updateEntry(nameObj.name, nameObj.value, nameObj.nHeight, CT_NEW); } else { LogPrintf("refreshName result : %s - ignored (not in the table)\n", qPrintable(nameObj.name)); } } }
void CNameMemPool::removeUnexpireConflicts (const std::set<valtype>& unexpired, std::list<CTransaction>& removed) { AssertLockHeld (pool.cs); BOOST_FOREACH (const valtype& name, unexpired) { LogPrint ("names", "unexpired: %s, mempool: %u\n", ValtypeToString (name).c_str (), mapNameRegs.count (name)); const NameTxMap::const_iterator mit = mapNameRegs.find (name); if (mit != mapNameRegs.end ()) { const CTxMemPool::txiter mit2 = pool.mapTx.find (mit->second); assert (mit2 != pool.mapTx.end ()); pool.removeRecursive (mit2->GetTx (), removed); } }
UniValue name_pending (const UniValue& params, bool fHelp) { if (fHelp || params.size () > 1) throw std::runtime_error ( "name_pending (\"name\")\n" "\nList unconfirmed name operations in the mempool.\n" "\nIf a name is given, only check for operations on this name.\n" "\nArguments:\n" "1. \"name\" (string, optional) only look for this name\n" "\nResult:\n" "[\n" " {\n" " \"op\": xxxx (string) the operation being performed\n" " \"name\": xxxx (string) the name operated on\n" " \"value\": xxxx (string) the name's new value\n" " \"txid\": xxxx (string) the txid corresponding to the operation\n" " \"ismine\": xxxx (boolean) whether the name is owned by the wallet\n" " },\n" " ...\n" "]\n" + HelpExampleCli ("name_pending", "") + HelpExampleCli ("name_pending", "\"d/domob\"") + HelpExampleRpc ("name_pending", "") ); #ifdef ENABLE_WALLET LOCK2 (pwalletMain ? &pwalletMain->cs_wallet : NULL, mempool.cs); #else LOCK (mempool.cs); #endif std::vector<uint256> txHashes; if (params.size () == 0) mempool.queryHashes (txHashes); else { const std::string name = params[0].get_str (); const valtype vchName = ValtypeFromString (name); const uint256 txid = mempool.getTxForName (vchName); if (!txid.IsNull ()) txHashes.push_back (txid); } UniValue arr(UniValue::VARR); for (std::vector<uint256>::const_iterator i = txHashes.begin (); i != txHashes.end (); ++i) { std::shared_ptr<const CTransaction> tx = mempool.get (*i); if (!tx || !tx->IsNamecoin ()) continue; for (const auto& txOut : tx->vout) { const CNameScript op(txOut.scriptPubKey); if (!op.isNameOp () || !op.isAnyUpdate ()) continue; const valtype vchName = op.getOpName (); const valtype vchValue = op.getOpValue (); const std::string name = ValtypeToString (vchName); const std::string value = ValtypeToString (vchValue); std::string strOp; switch (op.getNameOp ()) { case OP_NAME_FIRSTUPDATE: strOp = "name_firstupdate"; break; case OP_NAME_UPDATE: strOp = "name_update"; break; default: assert (false); } UniValue obj(UniValue::VOBJ); obj.push_back (Pair ("op", strOp)); obj.push_back (Pair ("name", name)); obj.push_back (Pair ("value", value)); obj.push_back (Pair ("txid", tx->GetHash ().GetHex ())); #ifdef ENABLE_WALLET isminetype mine = ISMINE_NO; if (pwalletMain) mine = IsMine (*pwalletMain, op.getAddress ()); const bool isMine = (mine & ISMINE_SPENDABLE); obj.push_back (Pair ("ismine", isMine)); #endif arr.push_back (obj); } } return arr; }
UniValue name_filter (const UniValue& params, bool fHelp) { if (fHelp || params.size () > 5) throw std::runtime_error ( "name_filter (\"regexp\" (\"maxage\" (\"from\" (\"nb\" (\"stat\")))))\n" "\nScan and list names matching a regular expression.\n" "\nArguments:\n" "1. \"regexp\" (string, optional) filter names with this regexp\n" "2. \"maxage\" (numeric, optional, default=36000) only consider names updated in the last \"maxage\" blocks; 0 means all names\n" "3. \"from\" (numeric, optional, default=0) return from this position onward; index starts at 0\n" "4. \"nb\" (numeric, optional, default=0) return only \"nb\" entries; 0 means all\n" "5. \"stat\" (string, optional) if set to the string \"stat\", print statistics instead of returning the names\n" "\nResult:\n" "[\n" + getNameInfoHelp (" ", ",") + " ...\n" "]\n" "\nExamples:\n" + HelpExampleCli ("name_filter", "\"\" 5") + HelpExampleCli ("name_filter", "\"^id/\"") + HelpExampleCli ("name_filter", "\"^id/\" 36000 0 0 \"stat\"") + HelpExampleRpc ("name_scan", "\"^d/\"") ); if (IsInitialBlockDownload ()) throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD, "Namecoin is downloading blocks..."); /* ********************** */ /* Interpret parameters. */ bool haveRegexp(false); boost::xpressive::sregex regexp; int maxage(36000), from(0), nb(0); bool stats(false); if (params.size () >= 1) { haveRegexp = true; regexp = boost::xpressive::sregex::compile (params[0].get_str ()); } if (params.size () >= 2) maxage = params[1].get_int (); if (maxage < 0) throw JSONRPCError (RPC_INVALID_PARAMETER, "'maxage' should be non-negative"); if (params.size () >= 3) from = params[2].get_int (); if (from < 0) throw JSONRPCError (RPC_INVALID_PARAMETER, "'from' should be non-negative"); if (params.size () >= 4) nb = params[3].get_int (); if (nb < 0) throw JSONRPCError (RPC_INVALID_PARAMETER, "'nb' should be non-negative"); if (params.size () >= 5) { if (params[4].get_str () != "stat") throw JSONRPCError (RPC_INVALID_PARAMETER, "fifth argument must be the literal string 'stat'"); stats = true; } /* ******************************************* */ /* Iterate over names to build up the result. */ UniValue names(UniValue::VARR); unsigned count(0); LOCK (cs_main); valtype name; CNameData data; std::unique_ptr<CNameIterator> iter(pcoinsTip->IterateNames ()); while (iter->next (name, data)) { const int age = chainActive.Height () - data.getHeight (); assert (age >= 0); if (maxage != 0 && age >= maxage) continue; if (haveRegexp) { const std::string nameStr = ValtypeToString (name); boost::xpressive::smatch matches; if (!boost::xpressive::regex_search (nameStr, matches, regexp)) continue; } if (from > 0) { --from; continue; } assert (from == 0); if (stats) ++count; else names.push_back (getNameInfo (name, data)); if (nb > 0) { --nb; if (nb == 0) break; } } /* ********************************************************** */ /* Return the correct result (take stats mode into account). */ if (stats) { UniValue res(UniValue::VOBJ); res.push_back (Pair ("blocks", chainActive.Height ())); res.push_back (Pair ("count", static_cast<int> (count))); return res; } return names; }