void CNameMemPool::removeConflicts (const CTransaction& tx, std::list<CTransaction>& removed) { AssertLockHeld (pool.cs); if (!tx.IsNamecoin ()) return; BOOST_FOREACH (const CTxOut& txout, tx.vout) { const CNameScript nameOp(txout.scriptPubKey); if (nameOp.isNameOp () && nameOp.getNameOp () == OP_NAME_FIRSTUPDATE) { const valtype& name = nameOp.getOpName (); 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; }
bool CCoinsViewDB::ValidateNameDB(CGameDB& gameDb) const { /* Skip for genesis block, since there is no game state available yet (test would fail below). There's not really anything to verify for the genesis block anyway. */ const uint256 blockHash = GetBestBlock(); if (blockHash.IsNull()) return true; /* It seems that there are no "const iterators" for LevelDB. Since we only need read operations on it, use a const-cast to get around that restriction. */ boost::scoped_ptr<CDBIterator> pcursor(const_cast<CDBWrapper*>(&db)->NewIterator()); pcursor->SeekToFirst(); /* Loop over the total database and read interesting things to memory. We later use that to check everything against each other. */ std::set<valtype> namesTotal; std::set<valtype> namesInDB; std::set<valtype> namesWithHistory; std::map<valtype, CAmount> namesInUTXO; for (; pcursor->Valid(); pcursor->Next()) { boost::this_thread::interruption_point(); char chType; if (!pcursor->GetKey(chType)) continue; switch (chType) { case DB_COINS: { CCoins coins; if (!pcursor->GetValue(coins)) return error("%s : failed to read coins", __func__); BOOST_FOREACH(const CTxOut& txout, coins.vout) if (!txout.IsNull()) { const CNameScript nameOp(txout.scriptPubKey); if (nameOp.isNameOp() && nameOp.isAnyUpdate()) { const valtype& name = nameOp.getOpName(); if (namesInUTXO.count(name) > 0) return error("%s : name %s duplicated in UTXO set", __func__, ValtypeToString(name).c_str()); namesInUTXO.insert(std::make_pair(nameOp.getOpName(), txout.nValue)); } } break; } case DB_NAME: { std::pair<char, valtype> key; if (!pcursor->GetKey(key) || key.first != DB_NAME) return error("%s : failed to read DB_NAME key", __func__); const valtype& name = key.second; CNameData data; if (!pcursor->GetValue(data)) return error("%s : failed to read name value", __func__); if (namesTotal.count(name) > 0) return error("%s : name %s duplicated in name index", __func__, ValtypeToString(name).c_str()); namesTotal.insert(name); assert(namesInDB.count(name) == 0); if (!data.isDead ()) namesInDB.insert(name); break; } case DB_NAME_HISTORY: { std::pair<char, valtype> key; if (!pcursor->GetKey(key) || key.first != DB_NAME_HISTORY) return error("%s : failed to read DB_NAME_HISTORY key", __func__); const valtype& name = key.second; if (namesWithHistory.count(name) > 0) return error("%s : name %s has duplicate history", __func__, ValtypeToString(name).c_str()); namesWithHistory.insert(name); break; } default: break; } } std::map<valtype, CAmount> namesInGame; GameState state(Params().GetConsensus()); if (!gameDb.get(blockHash, state)) return error("%s : failed to read game state", __func__); for (PlayerStateMap::const_iterator mi = state.players.begin(); mi != state.players.end(); ++mi) { const valtype cur = ValtypeFromString(mi->first); if (namesInGame.count(cur) > 0) return error("%s : name %s is duplicate in the game state", __func__, mi->first.c_str()); namesInGame.insert(std::make_pair(cur, mi->second.lockedCoins)); } /* Now verify the collected data. */ assert (namesTotal.size() >= namesInDB.size()); if (namesInGame != namesInUTXO) return error("%s : game state and name DB mismatch", __func__); BOOST_FOREACH(const valtype& name, namesInDB) if (namesInUTXO.count(name) == 0) return error("%s : name '%s' in DB but not UTXO set", __func__, ValtypeToString(name).c_str()); BOOST_FOREACH(const PAIRTYPE(valtype, CAmount)& pair, namesInUTXO) if (namesInDB.count(pair.first) == 0) return error("%s : name '%s' in UTXO set but not DB", __func__, ValtypeToString(pair.first).c_str()); if (fNameHistory) { BOOST_FOREACH(const valtype& name, namesWithHistory) if (namesTotal.count(name) == 0) return error("%s : history entry for name '%s' not in main DB", __func__, ValtypeToString(name).c_str()); } else if (!namesWithHistory.empty ())
bool CCoinsViewDB::ValidateNameDB() const { const uint256 blockHash = GetBestBlock(); int nHeight; if (blockHash.IsNull()) nHeight = 0; else nHeight = mapBlockIndex.find(blockHash)->second->nHeight; /* It seems that there are no "const iterators" for LevelDB. Since we only need read operations on it, use a const-cast to get around that restriction. */ boost::scoped_ptr<CDBIterator> pcursor(const_cast<CDBWrapper*>(&db)->NewIterator()); pcursor->SeekToFirst(); /* Loop over the total database and read interesting things to memory. We later use that to check everything against each other. */ std::map<valtype, unsigned> nameHeightsIndex; std::map<valtype, unsigned> nameHeightsData; std::set<valtype> namesInDB; std::set<valtype> namesInUTXO; std::set<valtype> namesWithHistory; for (; pcursor->Valid(); pcursor->Next()) { boost::this_thread::interruption_point(); char chType; if (!pcursor->GetKey(chType)) continue; switch (chType) { case DB_COINS: { CCoins coins; if (!pcursor->GetValue(coins)) return error("%s : failed to read coins", __func__); BOOST_FOREACH(const CTxOut& txout, coins.vout) if (!txout.IsNull()) { const CNameScript nameOp(txout.scriptPubKey); if (nameOp.isNameOp() && nameOp.isAnyUpdate()) { const valtype& name = nameOp.getOpName(); if (namesInUTXO.count(name) > 0) return error("%s : name %s duplicated in UTXO set", __func__, ValtypeToString(name).c_str()); namesInUTXO.insert(nameOp.getOpName()); } } break; } case DB_NAME: { std::pair<char, valtype> key; if (!pcursor->GetKey(key) || key.first != DB_NAME) return error("%s : failed to read DB_NAME key", __func__); const valtype& name = key.second; CNameData data; if (!pcursor->GetValue(data)) return error("%s : failed to read name value", __func__); if (nameHeightsData.count(name) > 0) return error("%s : name %s duplicated in name index", __func__, ValtypeToString(name).c_str()); nameHeightsData.insert(std::make_pair(name, data.getHeight())); /* Expiration is checked at height+1, because that matches how the UTXO set is cleared in ExpireNames. */ assert(namesInDB.count(name) == 0); if (!data.isExpired(nHeight + 1)) namesInDB.insert(name); break; } case DB_NAME_HISTORY: { std::pair<char, valtype> key; if (!pcursor->GetKey(key) || key.first != DB_NAME_HISTORY) return error("%s : failed to read DB_NAME_HISTORY key", __func__); const valtype& name = key.second; if (namesWithHistory.count(name) > 0) return error("%s : name %s has duplicate history", __func__, ValtypeToString(name).c_str()); namesWithHistory.insert(name); break; } case DB_NAME_EXPIRY: { std::pair<char, CNameCache::ExpireEntry> key; if (!pcursor->GetKey(key) || key.first != DB_NAME_EXPIRY) return error("%s : failed to read DB_NAME_EXPIRY key", __func__); const CNameCache::ExpireEntry& entry = key.second; const valtype& name = entry.name; if (nameHeightsIndex.count(name) > 0) return error("%s : name %s duplicated in expire idnex", __func__, ValtypeToString(name).c_str()); nameHeightsIndex.insert(std::make_pair(name, entry.nHeight)); break; } default: break; } } /* Now verify the collected data. */ assert (nameHeightsData.size() >= namesInDB.size()); if (nameHeightsIndex != nameHeightsData) return error("%s : name height data mismatch", __func__); BOOST_FOREACH(const valtype& name, namesInDB) if (namesInUTXO.count(name) == 0) return error("%s : name '%s' in DB but not UTXO set", __func__, ValtypeToString(name).c_str()); BOOST_FOREACH(const valtype& name, namesInUTXO) if (namesInDB.count(name) == 0) return error("%s : name '%s' in UTXO set but not DB", __func__, ValtypeToString(name).c_str()); if (fNameHistory) { BOOST_FOREACH(const valtype& name, namesWithHistory) if (nameHeightsData.count(name) == 0) return error("%s : history entry for name '%s' not in main DB", __func__, ValtypeToString(name).c_str()); } else if (!namesWithHistory.empty ())