diff --git a/src/RPCServer.cpp b/src/RPCServer.cpp index 2e8fbdc185..c1f59e5a1a 100644 --- a/src/RPCServer.cpp +++ b/src/RPCServer.cpp @@ -1460,11 +1460,11 @@ Json::Value RPCServer::doUnlAdd(Json::Value& params) std::string strNode = params[0u].asString(); std::string strComment = (params.size() == 2) ? params[1u].asString() : ""; - NewcoinAddress nodePublic; + NewcoinAddress naNodePublic; - if (nodePublic.setNodePublic(strNode)) + if (naNodePublic.setNodePublic(strNode)) { - theApp->getUNL().nodeAddPublic(nodePublic, strComment); + theApp->getUNL().nodeAddPublic(naNodePublic, UniqueNodeList::vsManual, strComment); return "adding node by public key"; } @@ -1474,8 +1474,6 @@ Json::Value RPCServer::doUnlAdd(Json::Value& params) return "adding node by domain"; } - - return "invalid params"; } // validation_create [||] @@ -1973,22 +1971,24 @@ Json::Value RPCServer::doUnlDefault(Json::Value& params) { return RPCError(rpcINVALID_PARAMS); } -// unl_delete +// unl_delete | Json::Value RPCServer::doUnlDelete(Json::Value& params) { - std::string strNodePublic = params[0u].asString(); + std::string strNode = params[0u].asString(); NewcoinAddress naNodePublic; - if (naNodePublic.setNodePublic(strNodePublic)) + if (naNodePublic.setNodePublic(strNode)) { - theApp->getUNL().nodeRemove(naNodePublic); + theApp->getUNL().nodeRemovePublic(naNodePublic); - return "removing node"; + return "removing node by public key"; } else { - return "invalid public key"; + theApp->getUNL().nodeRemoveDomain(strNode); + + return "removing node by domain"; } } diff --git a/src/UniqueNodeList.cpp b/src/UniqueNodeList.cpp index 50a73df507..1427e3db8a 100644 --- a/src/UniqueNodeList.cpp +++ b/src/UniqueNodeList.cpp @@ -9,6 +9,7 @@ #include "UniqueNodeList.h" #include "utils.h" +#include #include #include #include @@ -26,6 +27,7 @@ #define SECTION_VALIDATORS_URL "validators_url" // Limit pollution of database. +// YYY Move to config file. #define REFERRAL_VALIDATORS_MAX 50 #define REFERRAL_IPS_MAX 50 @@ -90,13 +92,10 @@ void UniqueNodeList::trustedLoad() mUNL.clear(); + // XXX Needs to limit by quanity and quality. SQL_FOREACH(db, "SELECT PublicKey FROM TrustedNodes WHERE Score != 0;") { - std::string strPublicKey; - - db->getStr("PublicKey", strPublicKey); - - mUNL.insert(strPublicKey); + mUNL.insert(db->getStrBinary("PublicKey")); } } @@ -169,12 +168,14 @@ void UniqueNodeList::scoreCompute() { strIndex umPulicIdx; // Map of public key to index. strIndex umDomainIdx; // Map of domain to index. - std::vector vsnNodes; + std::vector vsnNodes; // Index to scoring node. Database* db=theApp->getWalletDB()->getDB(); std::string strSql; + // For each entry in SeedDomains with a PublicKey: + // - Add an entry in umPulicIdx, umDomainIdx, and vsnNodes. { ScopedLock sl(theApp->getWalletDB()->getDBLock()); @@ -186,13 +187,9 @@ void UniqueNodeList::scoreCompute() } else { - std::string strDomain; - std::string strPublicKey; - std::string strSource; - - db->getStr("Domain", strDomain); - db->getStr("PublicKey", strPublicKey); - db->getStr("Source", strSource); + std::string strDomain = db->getStrBinary("Domain"); + std::string strPublicKey = db->getStrBinary("PublicKey"); + std::string strSource = db->getStrBinary("Source"); int iNode = vsnNodes.size(); @@ -212,6 +209,7 @@ void UniqueNodeList::scoreCompute() } } + // For debugging, print out initial scores. BOOST_FOREACH(scoreNode& sn, vsnNodes) { std::cerr << str(boost::format("%s| %d, %d, %d") @@ -227,6 +225,7 @@ void UniqueNodeList::scoreCompute() // std::cerr << str(boost::format("vsnNodes.size=%d") % vsnNodes.size()) << std::endl; // Step through growing list of nodes adding each validation list. + // - Each validator may have provided referals. Add those referals as validators. for (int iNode=0; iNode != vsnNodes.size(); iNode++) { scoreNode& sn = vsnNodes[iNode]; @@ -238,11 +237,9 @@ void UniqueNodeList::scoreCompute() SQL_FOREACH(db, str(boost::format("SELECT Referral FROM ValidatorReferrals WHERE Validator=%s ORDER BY Entry;") % db->escape(strValidator))) { - std::string strReferral; + std::string strReferral = db->getStrBinary("Referral"); int iReferral; - db->getStr("Referral", strReferral); - strIndex::iterator itEntry; NewcoinAddress na; @@ -335,11 +332,7 @@ void UniqueNodeList::scoreCompute() SQL_FOREACH(db, str(boost::format("SELECT PublicKey,Seen FROM TrustedNodes WHERE PublicKey IN (%s);") % strJoin(vstrPublicKeys.begin(), vstrPublicKeys.end(), ","))) { - std::string strPublicKey; - - db->getStr("PublicKey", strPublicKey); - - vsnNodes[umPulicIdx[strPublicKey]].iSeen = db->getNull("Seen") ? -1 : db->getInt("Seen"); + vsnNodes[umPulicIdx[db->getStrBinary("PublicKey")]].iSeen = db->getNull("Seen") ? -1 : db->getInt("Seen"); } } @@ -358,7 +351,7 @@ void UniqueNodeList::scoreCompute() std::string strSeen = sn.iSeen >= 0 ? str(boost::format("%d") % sn.iSeen) : "NULL"; vstrValues[iNode] = str(boost::format("(%s,%s,%s)") - % db->escape(sn.strValidator) + % sqlEscape(sn.strValidator) % sn.iScore % strSeen); @@ -372,6 +365,7 @@ void UniqueNodeList::scoreCompute() { ScopedLock sl(mUNLLock); + // XXX Should limit to scores above a certain minimum and limit to a certain number. mUNL.swap(usUNL); } @@ -387,11 +381,7 @@ void UniqueNodeList::scoreCompute() // For every IpReferral add a score for the IP and PORT. SQL_FOREACH(db, "SELECT Validator,COUNT(*) AS Count FROM IpReferrals GROUP BY Validator;") { - std::string strValidator; - - db->getStr("Validator", strValidator); - - umValidators[strValidator] = db->getInt("Count"); + umValidators[db->getStrBinary("Validator")] = db->getInt("Count"); // std::cerr << strValidator << ":" << db->getInt("Count") << std::endl; } @@ -418,13 +408,11 @@ void UniqueNodeList::scoreCompute() % db->escape(strValidator))) { score iPoints = iBase * (iEntries - iEntry) / iEntries; - std::string strIP; int iPort; - db->getStr("IP", strIP); iPort = db->getNull("Port") ? -1 : db->getInt("Port"); - std::pair< std::string, int> ep = std::make_pair(strIP, iPort); + std::pair< std::string, int> ep = std::make_pair(db->getStrBinary("IP"), iPort); epScore::iterator itEp = umScore.find(ep); @@ -491,6 +479,7 @@ void UniqueNodeList::scoreTimerHandler(const boost::system::error_code& err) } // Start a timer to update scores. +// <-- bNow: true, to force scoring for debugging. void UniqueNodeList::scoreNext(bool bNow) { // std::cerr << str(boost::format("scoreNext: mtpFetchUpdated=%s mtpScoreStart=%s mtpScoreUpdated=%s mtpScoreNext=%s") % mtpFetchUpdated % mtpScoreStart % mtpScoreUpdated % mtpScoreNext) << std::endl; @@ -534,6 +523,7 @@ void UniqueNodeList::fetchFinish() fetchNext(); } +// Called when we need to update scores. void UniqueNodeList::fetchDirty() { // Note update. @@ -633,9 +623,8 @@ void UniqueNodeList::processIps(const std::string& strSite, const NewcoinAddress // Persist ValidatorReferrals. void UniqueNodeList::processValidators(const std::string& strSite, const std::string& strValidatorsSrc, const NewcoinAddress& naNodePublic, section::mapped_type* pmtVecStrValidators) { - Database* db=theApp->getWalletDB()->getDB(); - - std::string strEscNodePublic = db->escape(naNodePublic.humanNodePublic()); + Database* db = theApp->getWalletDB()->getDB(); + std::string strNodePublic = naNodePublic.humanNodePublic(); std::cerr << str(boost::format("Validator: '%s' : '%s' : processing %d validators.") @@ -647,7 +636,8 @@ void UniqueNodeList::processValidators(const std::string& strSite, const std::st // Remove all current Validator's entries in ValidatorReferrals { ScopedLock sl(theApp->getWalletDB()->getDBLock()); - db->executeSQL(str(boost::format("DELETE FROM ValidatorReferrals WHERE Validator=%s;") % strEscNodePublic)); + + db->executeSQL(str(boost::format("DELETE FROM ValidatorReferrals WHERE Validator='%s';") % strNodePublic)); // XXX Check result. } @@ -655,28 +645,53 @@ void UniqueNodeList::processValidators(const std::string& strSite, const std::st if (pmtVecStrValidators && pmtVecStrValidators->size()) { std::vector vstrValues; - vstrValues.resize(MIN(pmtVecStrValidators->size(), REFERRAL_VALIDATORS_MAX)); + vstrValues.reserve(MIN(pmtVecStrValidators->size(), REFERRAL_VALIDATORS_MAX)); - int i = 0; + int iValues = 0; BOOST_FOREACH(std::string strReferral, *pmtVecStrValidators) { - if (i == REFERRAL_VALIDATORS_MAX) + if (iValues == REFERRAL_VALIDATORS_MAX) break; - vstrValues[i] = str(boost::format("(%s,%d,%s)") % strEscNodePublic % i % db->escape(strReferral)); - i++; + boost::smatch smMatch; + std::string strIP; - NewcoinAddress naValidator; + // domain comment? + // public_key comment? + static boost::regex reReferral("\\`\\s*(\\S+)(?:\\s+(\\d+))?\\s*\\'"); - if (naValidator.setNodePublic(strReferral)) + if (!boost::regex_match(strReferral, smMatch, reReferral)) { - // A public key. - // XXX Schedule for CAS lookup. + std::cerr + << str(boost::format("Validator: '%s' ["SECTION_VALIDATORS"]: rejecting '%s'") + % strSite % strReferral) + << std::endl; } else { - // A domain: need to look it up. - nodeAddDomain(strReferral, vsReferral); + std::string strRefered = smMatch[1]; + std::string strComment = smMatch[2]; + NewcoinAddress naValidator; + + if (naValidator.setNodePublic(strRefered)) + { + // A public key. + // XXX Schedule for CAS lookup. + nodeAddPublic(naValidator, vsReferral, strComment); + + vstrValues.push_back(str(boost::format("('%s',%d,'%s')") % strNodePublic % iValues % naValidator.humanNodePublic())); + } + else + { + // A domain: need to look it up. + boost::trim(strRefered); + boost::to_lower(strRefered); + nodeAddDomain(strRefered, vsReferral, strComment); + + vstrValues.push_back(str(boost::format("('%s',%d,%s)") % strNodePublic % iValues % sqlEscape(strRefered))); + } + + iValues++; } } @@ -707,7 +722,7 @@ void UniqueNodeList::responseIps(const std::string& strSite, const NewcoinAddres // Process section [ips_url]. // If we have a section with a single entry, fetch the url and process it. -void UniqueNodeList::getIpsUrl(NewcoinAddress naNodePublic, section secSite) +void UniqueNodeList::getIpsUrl(const NewcoinAddress& naNodePublic, section secSite) { std::string strIpsUrl; std::string strDomain; @@ -733,7 +748,7 @@ void UniqueNodeList::getIpsUrl(NewcoinAddress naNodePublic, section secSite) } // Given a section with validators, parse and persist it. -void UniqueNodeList::responseValidators(const std::string& strValidatorsUrl, NewcoinAddress naNodePublic, section secSite, const std::string& strSite, const boost::system::error_code& err, const std::string strValidatorsFile) +void UniqueNodeList::responseValidators(const std::string& strValidatorsUrl, const NewcoinAddress& naNodePublic, section secSite, const std::string& strSite, const boost::system::error_code& err, const std::string strValidatorsFile) { if (!err) { @@ -746,7 +761,7 @@ void UniqueNodeList::responseValidators(const std::string& strValidatorsUrl, New } // Process section [validators_url]. -void UniqueNodeList::getValidatorsUrl(NewcoinAddress naNodePublic, section secSite) +void UniqueNodeList::getValidatorsUrl(const NewcoinAddress& naNodePublic, section secSite) { std::string strValidatorsUrl; std::string strDomain; @@ -772,7 +787,7 @@ void UniqueNodeList::getValidatorsUrl(NewcoinAddress naNodePublic, section secSi } // Process a newcoin.txt. -void UniqueNodeList::processFile(const std::string strDomain, NewcoinAddress naNodePublic, section secSite) +void UniqueNodeList::processFile(const std::string strDomain, const NewcoinAddress& naNodePublic, section secSite) { // // Process Validators @@ -981,7 +996,7 @@ void UniqueNodeList::fetchNext() tpNow = boost::posix_time::second_clock::universal_time(); std::cerr << str(boost::format("fetchNext: iNext=%s tpNext=%s tpNow=%s") % iNext % tpNext % tpNow) << std::endl; - db->getStr("Domain", strDomain); + strDomain = db->getStrBinary("Domain"); db->endIterRows(); } @@ -1057,48 +1072,7 @@ int UniqueNodeList::iSourceScore(validatorSource vsWhy) return iScore; } -// Queue a domain for a single attempt fetch a newcoin.txt. -// --> strComment: only used on vsManual -// YYY As a lot of these may happen at once, would be nice to wrap multiple calls in a transaction. -void UniqueNodeList::nodeAddDomain(const std::string& strDomain, validatorSource vsWhy, std::string strComment) -{ - // YYY Would be best to verify strDomain is a valid domain. - // std::cerr << str(boost::format("nodeAddDomain: '%s' %c '%s'") - // % strDomain - // % vsWhy - // % strComment) << std::endl; - - seedDomain sdCurrent; - - bool bFound = getSeedDomains(strDomain, sdCurrent); - bool bChanged = false; - - if (!bFound) - { - sdCurrent.strDomain = strDomain; - sdCurrent.tpNext = boost::posix_time::second_clock::universal_time(); - } - - // Promote source, if needed. - if (!bFound || iSourceScore(vsWhy) >= iSourceScore(sdCurrent.vsSource)) - { - sdCurrent.vsSource = vsWhy; - bChanged = true; - } - - if (vsManual == vsWhy) - { - // A manual add forces immediate scan. - sdCurrent.tpNext = boost::posix_time::second_clock::universal_time(); - sdCurrent.strComment = strComment; - bChanged = true; - } - - if (bChanged) - setSeedDomains(sdCurrent, true); -} - -// Retrieve a SeedDomain for DB. +// Retrieve a SeedDomain from DB. bool UniqueNodeList::getSeedDomains(const std::string& strDomain, seedDomain& dstSeedDomain) { bool bResult; @@ -1113,13 +1087,12 @@ bool UniqueNodeList::getSeedDomains(const std::string& strDomain, seedDomain& ds if (bResult) { std::string strPublicKey; - std::string strSource; int iNext; int iScan; int iFetch; std::string strSha256; - db->getStr("Domain", dstSeedDomain.strDomain); + dstSeedDomain.strDomain = db->getStrBinary("Domain"); if (!db->getNull("PublicKey") && db->getStr("PublicKey", strPublicKey)) { @@ -1130,14 +1103,16 @@ bool UniqueNodeList::getSeedDomains(const std::string& strDomain, seedDomain& ds dstSeedDomain.naPublicKey.clear(); } - db->getStr("Source", strSource); + std::string strSource = db->getStrBinary("Source"); dstSeedDomain.vsSource = static_cast(strSource[0]); + iNext = db->getInt("Next"); dstSeedDomain.tpNext = ptFromSeconds(iNext); iScan = db->getInt("Scan"); dstSeedDomain.tpScan = ptFromSeconds(iScan); iFetch = db->getInt("Fetch"); dstSeedDomain.tpFetch = ptFromSeconds(iFetch); + if (!db->getNull("Sha256") && db->getStr("Sha256", strSha256)) { dstSeedDomain.iSha256.SetHex(strSha256); @@ -1146,7 +1121,7 @@ bool UniqueNodeList::getSeedDomains(const std::string& strDomain, seedDomain& ds { dstSeedDomain.iSha256.zero(); } - db->getStr("Comment", dstSeedDomain.strComment); + dstSeedDomain.strComment = db->getStrBinary("Comment"); db->endIterRows(); } @@ -1191,68 +1166,227 @@ void UniqueNodeList::setSeedDomains(const seedDomain& sdSource, bool bNext) } } -// Add a trusted node. Called by RPC or other source. -// XXX Broken should operate on seeds. -void UniqueNodeList::nodeAddPublic(const NewcoinAddress& naNodePublic, const std::string& strComment) +// Queue a domain for a single attempt fetch a newcoin.txt. +// --> strComment: only used on vsManual +// YYY As a lot of these may happen at once, would be nice to wrap multiple calls in a transaction. +void UniqueNodeList::nodeAddDomain(std::string strDomain, validatorSource vsWhy, const std::string& strComment) { - std::string strPublicKey = naNodePublic.humanNodePublic(); + boost::trim(strDomain); + boost::to_lower(strDomain); + // YYY Would be best to verify strDomain is a valid domain. + // std::cerr << str(boost::format("nodeAddDomain: '%s' %c '%s'") + // % strDomain + // % vsWhy + // % strComment) << std::endl; + + seedDomain sdCurrent; + + bool bFound = getSeedDomains(strDomain, sdCurrent); + bool bChanged = false; + + if (!bFound) { - Database* db=theApp->getWalletDB()->getDB(); - ScopedLock sl(theApp->getWalletDB()->getDBLock()); + sdCurrent.strDomain = strDomain; + sdCurrent.tpNext = boost::posix_time::second_clock::universal_time(); + } - if( db->executeSQL(str(boost::format("SELECT count(*) from TrustedNodes where PublicKey=%s;") % db->escape(strPublicKey))) && - db->startIterRows() && db->getInt(0)==1 ) - { // exists. update the comment - db->executeSQL(str(boost::format("UPDATE TrustedNodes set Comment=%s where PublicKey=%s;") % db->escape(strComment) % db->escape(strPublicKey) )); - }else - { // new node - db->executeSQL(str(boost::format("INSERT INTO TrustedNodes (PublicKey,Comment) values (%s,%s);") - % db->escape(strPublicKey) % db->escape(strComment))); + // Promote source, if needed. + if (!bFound || iSourceScore(vsWhy) >= iSourceScore(sdCurrent.vsSource)) + { + sdCurrent.vsSource = vsWhy; + bChanged = true; + } + + if (vsManual == vsWhy) + { + // A manual add forces immediate scan. + sdCurrent.tpNext = boost::posix_time::second_clock::universal_time(); + sdCurrent.strComment = strComment; + bChanged = true; + } + + if (bChanged) + setSeedDomains(sdCurrent, true); +} + +// Retrieve a SeedNode from DB. +bool UniqueNodeList::getSeedNodes(const NewcoinAddress& naNodePublic, seedNode& dstSeedNode) +{ + bool bResult; + Database* db=theApp->getWalletDB()->getDB(); + + std::string strSql = str(boost::format("SELECT * FROM SeedNodes WHERE PublicKey='%s';") + % naNodePublic.humanNodePublic()); + + ScopedLock sl(theApp->getWalletDB()->getDBLock()); + + bResult = db->executeSQL(strSql) && db->startIterRows(); + if (bResult) + { + std::string strPublicKey; + std::string strSource; + int iNext; + int iScan; + int iFetch; + std::string strSha256; + + if (!db->getNull("PublicKey") && db->getStr("PublicKey", strPublicKey)) + { + dstSeedNode.naPublicKey.setNodePublic(strPublicKey); + } + else + { + dstSeedNode.naPublicKey.clear(); } - + strSource = db->getStrBinary("Source"); + dstSeedNode.vsSource = static_cast(strSource[0]); + + iNext = db->getInt("Next"); + dstSeedNode.tpNext = ptFromSeconds(iNext); + iScan = db->getInt("Scan"); + dstSeedNode.tpScan = ptFromSeconds(iScan); + iFetch = db->getInt("Fetch"); + dstSeedNode.tpFetch = ptFromSeconds(iFetch); + + if (!db->getNull("Sha256") && db->getStr("Sha256", strSha256)) + { + dstSeedNode.iSha256.SetHex(strSha256); + } + else + { + dstSeedNode.iSha256.zero(); + } + dstSeedNode.strComment = db->getStrBinary("Comment"); + + db->endIterRows(); } - { - ScopedLock slUNL(mUNLLock); - - mUNL.insert(strPublicKey); - } + return bResult; } -// XXX Broken should operate on seeds. -void UniqueNodeList::nodeRemove(NewcoinAddress naNodePublic) +// Persist a SeedNode. +// <-- bNext: true, to do fetching if needed. +void UniqueNodeList::setSeedNodes(const seedNode& snSource, bool bNext) { - std::string strPublicKey = naNodePublic.humanNodePublic(); + Database* db=theApp->getWalletDB()->getDB(); + + int iNext = iToSeconds(snSource.tpNext); + int iScan = iToSeconds(snSource.tpScan); + int iFetch = iToSeconds(snSource.tpFetch); + + // std::cerr << str(boost::format("setSeedNodes: iNext=%s tpNext=%s") % iNext % sdSource.tpNext) << std::endl; + + assert(snSource.naPublicKey.isValid()); + + std::string strSql = str(boost::format("REPLACE INTO SeedNodes (PublicKey,Source,Next,Scan,Fetch,Sha256,Comment) VALUES ('%s', '%c', %d, %d, %d, '%s', %s);") + % snSource.naPublicKey.humanNodePublic() + % static_cast(snSource.vsSource) + % iNext + % iScan + % iFetch + % snSource.iSha256.GetHex() + % sqlEscape(snSource.strComment) + ); + + { + ScopedLock sl(theApp->getWalletDB()->getDBLock()); + + if (!db->executeSQL(strSql)) + { + // XXX Check result. + std::cerr << "setSeedNodes: failed." << std::endl; + } + } + +#if 0 + // YYY When we have a cas schedule lookups similar to this. + if (bNext && (mtpFetchNext.is_not_a_date_time() || mtpFetchNext > snSource.tpNext)) + { + // Schedule earlier wake up. + fetchNext(); + } +#else + fetchDirty(); +#endif +} + +// Add a trusted node. Called by RPC or other source. +void UniqueNodeList::nodeAddPublic(const NewcoinAddress& naNodePublic, validatorSource vsWhy, const std::string& strComment) +{ + seedNode snCurrent; + + bool bFound = getSeedNodes(naNodePublic, snCurrent); + bool bChanged = false; + + if (!bFound) + { + snCurrent.naPublicKey = naNodePublic; + snCurrent.tpNext = boost::posix_time::second_clock::universal_time(); + } + + // Promote source, if needed. + if (!bFound || iSourceScore(vsWhy) >= iSourceScore(snCurrent.vsSource)) + { + snCurrent.vsSource = vsWhy; + bChanged = true; + } + + if (vsManual == vsWhy) + { + // A manual add forces immediate scan. + snCurrent.tpNext = boost::posix_time::second_clock::universal_time(); + snCurrent.strComment = strComment; + bChanged = true; + } + + if (bChanged) + setSeedNodes(snCurrent, true); +} + +void UniqueNodeList::nodeRemovePublic(const NewcoinAddress& naNodePublic) +{ + { + Database* db=theApp->getWalletDB()->getDB(); + ScopedLock sl(theApp->getWalletDB()->getDBLock()); + + db->executeSQL(str(boost::format("DELETE FROM SeedNodes WHERE PublicKey=%s") % naNodePublic.humanNodePublic())); + } + + // YYY Only dirty on successful delete. + fetchDirty(); +} + +void UniqueNodeList::nodeRemoveDomain(std::string strDomain) +{ + boost::trim(strDomain); + boost::to_lower(strDomain); { Database* db=theApp->getWalletDB()->getDB(); ScopedLock sl(theApp->getWalletDB()->getDBLock()); - db->executeSQL(str(boost::format("DELETE FROM TrustedNodes where PublicKey=%s") % db->escape(strPublicKey))); + db->executeSQL(str(boost::format("DELETE FROM SeedDomains WHERE Domain=%s") % sqlEscape(strDomain))); } - { - ScopedLock slUNL(mUNLLock); - mUNL.erase(strPublicKey); - } + // YYY Only dirty on successful delete. + fetchDirty(); } -// XXX Broken should operate on seeds. void UniqueNodeList::nodeReset() { { Database* db=theApp->getWalletDB()->getDB(); ScopedLock sl(theApp->getWalletDB()->getDBLock()); - db->executeSQL("DELETE FROM TrustedNodes"); - } - { - ScopedLock slUNL(mUNLLock); - mUNL.clear(); + // XXX Check results. + db->executeSQL("DELETE FROM SeedDomains"); + db->executeSQL("DELETE FROM SeedNodes"); } + + fetchDirty(); } Json::Value UniqueNodeList::getUnlJson() @@ -1264,16 +1398,10 @@ Json::Value UniqueNodeList::getUnlJson() ScopedLock sl(theApp->getWalletDB()->getDBLock()); SQL_FOREACH(db, "SELECT * FROM TrustedNodes;") { - std::string strPublicKey; - std::string strComment; - - db->getStr("PublicKey", strPublicKey); - db->getStr("Comment", strComment); - Json::Value node(Json::objectValue); - node["publicKey"] = strPublicKey; - node["comment"] = strComment; + node["publicKey"] = db->getStrBinary("PublicKey"); + node["comment"] = db->getStrBinary("Comment"); ret.append(node); } diff --git a/src/UniqueNodeList.h b/src/UniqueNodeList.h index 40c6d99841..622fd589c8 100644 --- a/src/UniqueNodeList.h +++ b/src/UniqueNodeList.h @@ -47,6 +47,7 @@ private: boost::recursive_mutex mUNLLock; // XXX Make this faster, make this the contents vector unsigned char or raw public key. + // XXX Contents needs to based on score. boost::unordered_set mUNL; bool miscLoad(); @@ -63,6 +64,16 @@ private: std::string strComment; } seedDomain; + typedef struct { + NewcoinAddress naPublicKey; + validatorSource vsSource; + boost::posix_time::ptime tpNext; + boost::posix_time::ptime tpScan; + boost::posix_time::ptime tpFetch; + uint256 iSha256; + std::string strComment; + } seedNode; + // Used to distribute scores. typedef struct { int iScore; @@ -104,28 +115,32 @@ private: void fetchProcess(std::string strDomain); void fetchTimerHandler(const boost::system::error_code& err); - void getValidatorsUrl(NewcoinAddress naNodePublic, section secSite); - void getIpsUrl(NewcoinAddress naNodePublic, section secSite); + void getValidatorsUrl(const NewcoinAddress& naNodePublic, section secSite); + void getIpsUrl(const NewcoinAddress& naNodePublic, section secSite); void responseIps(const std::string& strSite, const NewcoinAddress& naNodePublic, const boost::system::error_code& err, const std::string strIpsFile); - void responseValidators(const std::string& strValidatorsUrl, NewcoinAddress naNodePublic, section secSite, const std::string& strSite, const boost::system::error_code& err, const std::string strValidatorsFile); + void responseValidators(const std::string& strValidatorsUrl, const NewcoinAddress& naNodePublic, section secSite, const std::string& strSite, const boost::system::error_code& err, const std::string strValidatorsFile); void processIps(const std::string& strSite, const NewcoinAddress& naNodePublic, section::mapped_type* pmtVecStrIps); void processValidators(const std::string& strSite, const std::string& strValidatorsSrc, const NewcoinAddress& naNodePublic, section::mapped_type* pmtVecStrValidators); - void processFile(const std::string strDomain, NewcoinAddress naNodePublic, section secSite); + void processFile(const std::string strDomain, const NewcoinAddress& naNodePublic, section secSite); bool getSeedDomains(const std::string& strDomain, seedDomain& dstSeedDomain); void setSeedDomains(const seedDomain& dstSeedDomain, bool bNext); + bool getSeedNodes(const NewcoinAddress& naNodePublic, seedNode& dstSeedNode); + void setSeedNodes(const seedNode& snSource, bool bNext); + public: UniqueNodeList(boost::asio::io_service& io_service); // Begin processing. void start(); - void nodeAddPublic(const NewcoinAddress& naNodePublic, const std::string& strComment); - void nodeAddDomain(const std::string& strDomain, validatorSource vsWhy, std::string strComment=""); - void nodeRemove(NewcoinAddress naNodePublic); + void nodeAddPublic(const NewcoinAddress& naNodePublic, validatorSource vsWhy, const std::string& strComment); + void nodeAddDomain(std::string strDomain, validatorSource vsWhy, const std::string& strComment=""); + void nodeRemovePublic(const NewcoinAddress& naNodePublic); + void nodeRemoveDomain(std::string strDomain); void nodeDefault(const std::string& strValidators); void nodeReset();