diff --git a/newcoind.cfg b/newcoind.cfg index 21ffc677c..b97fef5f2 100644 --- a/newcoind.cfg +++ b/newcoind.cfg @@ -31,7 +31,14 @@ # Note: $XDG_CONFIG_HOME defaults to $HOME/.config # $XDG_DATA_HOME defaults to $HOME/.local/share # +# [validators_site]: +# Specifies where to find validators.txt for UNL boostrapping and RPC command unl_network. +# During alpha testing, this defaults to: redstem.com +# +# Example: newcoin.org +# # [unl_default]: +# XXX This should be called: [validators_file] # Specifies how to bootstrap the UNL list. The UNL list is based on a # validators.txt file and is maintained in the databases. When newcoind # starts up, if the databases are missing or are obsolete due to an upgrade @@ -48,6 +55,16 @@ # Examples: C:/home/johndoe/newcoin/validators.txt # /home/johndoe/newcoin/validators.txt # +# [validators]: +# List of nodes to accept as validators speficied by public key or domain. +# +# For domains, newcoind will probe for https web servers at the specied +# domain in the following order: newcoin.DOMAIN, www.DOMAIN, DOMAIN +# +# Examples: redstem.com +# n9KorY8QtTdRx7TVDpwnG9NvyxsDwHUKUEeDLY3AkiGncVaSXZi5 +# n9MqiExBcoG19UXwoLjBJnhsxEhAZMuWwJDRdkyDz1EkEkwzQTNt John Doe +# # [peer_ip]: # IP address or domain to bind to allow external connections from peers. # Defaults to not allow external connections from peers. @@ -104,4 +121,4 @@ snTBDmrhUK3znvF8AaQURLm4UCkbS [unl_default] -validators.txt \ No newline at end of file +validators.txt diff --git a/src/Config.cpp b/src/Config.cpp index 176bb2b52..f399b0596 100644 --- a/src/Config.cpp +++ b/src/Config.cpp @@ -1,14 +1,11 @@ #include "Config.h" -#include "ParseSection.h" #include "utils.h" #include #include #include -#define CONFIG_FILE_NAME SYSTEM_NAME "d.cfg" // newcoind.cfg - #define SECTION_ACCOUNT_PROBE_MAX "account_probe_max" #define SECTION_FEE_ACCOUNT_CREATE "fee_account_create" #define SECTION_FEE_DEFAULT "fee_default" @@ -28,6 +25,8 @@ #define SECTION_VALIDATION_SEED "validation_seed" #define SECTION_WEBSOCKET_IP "websocket_ip" #define SECTION_WEBSOCKET_PORT "websocket_port" +#define SECTION_VALIDATORS "validators" +#define SECTION_VALIDATORS_SITE "validators_site" // Fees are in XNB. #define DEFAULT_FEE_ACCOUNT_CREATE 1000 @@ -143,6 +142,8 @@ void Config::setup(const std::string& strConf) ACCOUNT_PROBE_MAX = 10; + VALIDATORS_SITE = DEFAULT_VALIDATORS_SITE; + load(); } @@ -170,6 +171,17 @@ void Config::load() section secConfig = ParseSection(strConfigFile, true); std::string strTemp; + section::mapped_type* smtTmp; + + smtTmp = sectionEntries(secConfig, SECTION_VALIDATORS); + if (smtTmp) + { + VALIDATORS = *smtTmp; + sectionEntriesPrint(&VALIDATORS, SECTION_VALIDATORS); + } + + (void) sectionSingleB(secConfig, SECTION_VALIDATORS_SITE, VALIDATORS_SITE); + (void) sectionSingleB(secConfig, SECTION_PEER_IP, PEER_IP); if (sectionSingleB(secConfig, SECTION_PEER_PORT, strTemp)) diff --git a/src/Config.h b/src/Config.h index 10d1a1ce1..693b00d37 100644 --- a/src/Config.h +++ b/src/Config.h @@ -2,14 +2,14 @@ #define __CONFIG__ #include "types.h" -#include "SerializedTypes.h" #include "NewcoinAddress.h" +#include "ParseSection.h" +#include "SerializedTypes.h" #include #include #define SYSTEM_NAME "newcoin" -#define VALIDATORS_SITE "redstem.com" #define SYSTEM_CURRENCY_CODE "XNS" #define SYSTEM_CURRENCY_PRECISION 6 @@ -18,6 +18,9 @@ #define SYSTEM_CURRENCY_PARTS 1000000ull // 10^SYSTEM_CURRENCY_PRECISION #define SYSTEM_CURRENCY_START (SYSTEM_CURRENCY_GIFT*SYSTEM_CURRENCY_USERS*SYSTEM_CURRENCY_PARTS) +#define CONFIG_FILE_NAME SYSTEM_NAME "d.cfg" // newcoind.cfg + +#define DEFAULT_VALIDATORS_SITE "redstem.com" #define VALIDATORS_FILE_NAME "validators.txt" const int SYSTEM_PEER_PORT = 6561; @@ -46,6 +49,9 @@ public: boost::filesystem::path DATA_DIR; boost::filesystem::path UNL_DEFAULT; + std::string VALIDATORS_SITE; // Where to find validators.txt on the Internet. + std::vector VALIDATORS; // Validators from newcoind.cfg + // Network parameters int NETWORK_START_TIME; // The Unix time we start ledger 0 int TRANSACTION_FEE_BASE; diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index 4ab170404..2883864db 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -227,7 +227,6 @@ void LedgerConsensus::createDisputes(SHAMap::pointer m1, SHAMap::pointer m2) m1->compare(m2, differences, 16384); for(SHAMap::SHAMapDiff::iterator pos = differences.begin(), end = differences.end(); pos != end; ++pos) { // create disputed transactions (from the ledger that has them) - Log(lsTRACE) << "Transaction now in dispute: " << pos->first.GetHex(); if (pos->second.first) { assert(!pos->second.second); @@ -521,7 +520,7 @@ void LedgerConsensus::propose(const std::vector& added, const std::vect void LedgerConsensus::addDisputedTransaction(const uint256& txID, const std::vector& tx) { - Log(lsTRACE) << "Transacstion " << txID.GetHex() << " is disputed"; + Log(lsTRACE) << "Transaction " << txID.GetHex() << " is disputed"; boost::unordered_map::iterator it = mDisputes.find(txID); if (it != mDisputes.end()) return; @@ -649,7 +648,6 @@ void LedgerConsensus::applyTransaction(TransactionEngine& engine, SerializedTran else { Log(lsINFO) << " hard fail"; - assert(!ledger->hasTransaction(txn->getTransactionID())); } #ifndef TRUST_NETWORK } diff --git a/src/ParseSection.cpp b/src/ParseSection.cpp index e0fe2425d..839d3c85e 100644 --- a/src/ParseSection.cpp +++ b/src/ParseSection.cpp @@ -1,4 +1,5 @@ #include "ParseSection.h" +#include "utils.h" #include #include @@ -32,6 +33,8 @@ section ParseSection(const std::string& strInput, const bool bTrim) if (strValue.empty() || strValue[0] == '#') { // Blank line or comment, do nothing. + + nothing(); } else if (strValue[0] == '[' && strValue[strValue.length()-1] == ']') { // New section. @@ -41,29 +44,37 @@ section ParseSection(const std::string& strInput, const bool bTrim) } else { - // Another line in a section. + // Another line for section. if (bTrim) boost::algorithm::trim(strValue); - secResult[strSection].push_back(strValue); + if (!strValue.empty()) + secResult[strSection].push_back(strValue); } } return secResult; } -void PrintSection(section secInput) +void sectionEntriesPrint(std::vector* vspEntries, const std::string& strSection) +{ + std::cerr << "[" << strSection << "]" << std::endl; + + if (vspEntries) + { + BOOST_FOREACH(std::string& strValue, *vspEntries) + { + std::cerr << strValue << std::endl; + } + } +} + +void sectionPrint(section secInput) { - std::cerr << "PrintSection>" << std::endl; BOOST_FOREACH(section::value_type& pairSection, secInput) { - std::cerr << "[" << pairSection.first << "]" << std::endl; - BOOST_FOREACH(std::string& value, pairSection.second) - { - std::cerr << value << std::endl; - } + sectionEntriesPrint(&pairSection.second, pairSection.first); } - std::cerr << "PrintSection<" << std::endl; } section::mapped_type* sectionEntries(section& secSource, const std::string& strSection) diff --git a/src/ParseSection.h b/src/ParseSection.h index 76095416a..ca60f26aa 100644 --- a/src/ParseSection.h +++ b/src/ParseSection.h @@ -8,7 +8,8 @@ typedef std::map > section; section ParseSection(const std::string& strInput, const bool bTrim); -void PrintSection(section secInput); +void sectionPrint(section secInput); +void sectionEntriesPrint(std::vector* vspEntries, const std::string& strSection); bool sectionSingleB(section& secSource, const std::string& strSection, std::string& strValue); int sectionCount(section& secSource, const std::string& strSection); section::mapped_type* sectionEntries(section& secSource, const std::string& strSection); diff --git a/src/RPCServer.cpp b/src/RPCServer.cpp index f663219ee..0395d52a2 100644 --- a/src/RPCServer.cpp +++ b/src/RPCServer.cpp @@ -1926,7 +1926,7 @@ Json::Value RPCServer::doUnlList(Json::Value& params) // Populate the UNL from a local validators.txt file. Json::Value RPCServer::doUnlLoad(Json::Value& params) { - if (!theApp->getUNL().nodeLoad()) + if (theConfig.UNL_DEFAULT.empty() || !theApp->getUNL().nodeLoad(theConfig.UNL_DEFAULT)) { return RPCError(rpcLOAD_FAILED); } diff --git a/src/UniqueNodeList.cpp b/src/UniqueNodeList.cpp index 867bf2fe5..c49bfc70e 100644 --- a/src/UniqueNodeList.cpp +++ b/src/UniqueNodeList.cpp @@ -692,10 +692,11 @@ void UniqueNodeList::processIps(const std::string& strSite, const NewcoinAddress // --> strValidatorsSrc: source details for display // --> naNodePublic: remote source public key - not valid for local // --> vsWhy: reason for adding validator to SeedDomains or SeedNodes. -void UniqueNodeList::processValidators(const std::string& strSite, const std::string& strValidatorsSrc, const NewcoinAddress& naNodePublic, validatorSource vsWhy, section::mapped_type* pmtVecStrValidators) +int UniqueNodeList::processValidators(const std::string& strSite, const std::string& strValidatorsSrc, const NewcoinAddress& naNodePublic, validatorSource vsWhy, section::mapped_type* pmtVecStrValidators) { Database* db = theApp->getWalletDB()->getDB(); - std::string strNodePublic = naNodePublic.isValid() ? naNodePublic.humanNodePublic() : "local"; + std::string strNodePublic = naNodePublic.isValid() ? naNodePublic.humanNodePublic() : strValidatorsSrc; + int iValues = 0; std::cerr << str(boost::format("Validator: '%s' : '%s' : processing %d validators.") @@ -718,7 +719,6 @@ void UniqueNodeList::processValidators(const std::string& strSite, const std::st vstrValues.reserve(MIN(pmtVecStrValidators->size(), REFERRAL_VALIDATORS_MAX)); - int iValues = 0; BOOST_FOREACH(std::string strReferral, *pmtVecStrValidators) { if (iValues == REFERRAL_VALIDATORS_MAX) @@ -734,7 +734,7 @@ void UniqueNodeList::processValidators(const std::string& strSite, const std::st if (!boost::regex_match(strReferral, smMatch, reReferral)) { std::cerr - << str(boost::format("Validator: '%s' ["SECTION_VALIDATORS"]: rejecting '%s'") + << str(boost::format("Validator: '%s' ["SECTION_VALIDATORS"]: rejecting line: '%s'") % strSite % strReferral) << std::endl; } @@ -744,7 +744,7 @@ void UniqueNodeList::processValidators(const std::string& strSite, const std::st std::string strComment = smMatch[2]; NewcoinAddress naValidator; - // std::cerr << str(boost::format("Validator: '%s' : '%s'") % strRefered % strComment) << std::endl; + std::cerr << str(boost::format("Validator='%s', Comment='%s'") % strRefered % strComment) << std::endl; if (naValidator.setNodePublic(strRefered)) { @@ -781,6 +781,8 @@ void UniqueNodeList::processValidators(const std::string& strSite, const std::st } fetchDirty(); + + return iValues; } // Given a section with IPs, parse and persist it for a validator. @@ -823,7 +825,7 @@ void UniqueNodeList::getIpsUrl(const NewcoinAddress& naNodePublic, section secSi } } -// Given a section with validators, parse and persist it. +// After fetching a newcoin.txt from a web site, given a section with validators, parse and persist it. 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) @@ -1137,10 +1139,11 @@ int UniqueNodeList::iSourceScore(validatorSource vsWhy) int iScore = 0; switch (vsWhy) { + case vsConfig: iScore = 1500; break; case vsManual: iScore = 1500; break; + case vsReferral: iScore = 0; break; case vsValidator: iScore = 1000; break; case vsWeb: iScore = 200; break; - case vsReferral: iScore = 0; break; default: throw std::runtime_error("Internal error: bad validatorSource."); } @@ -1485,34 +1488,34 @@ Json::Value UniqueNodeList::getUnlJson() return ret; } -bool UniqueNodeList::nodeLoad() +bool UniqueNodeList::nodeLoad(boost::filesystem::path pConfig) { - if (theConfig.UNL_DEFAULT.empty()) + if (pConfig.empty()) { - std::cerr << "UNL_DEFAULT not specified." << std::endl; + std::cerr << VALIDATORS_FILE_NAME " path not specified." << std::endl; return false; } - if (!boost::filesystem::exists(theConfig.UNL_DEFAULT)) + if (!boost::filesystem::exists(pConfig)) { - std::cerr << str(boost::format("UNL_DEFAULT not found: %s") % theConfig.UNL_DEFAULT) << std::endl; + std::cerr << str(boost::format(VALIDATORS_FILE_NAME " not found: %s") % pConfig) << std::endl; return false; } - if (!boost::filesystem::is_regular_file(theConfig.UNL_DEFAULT)) + if (!boost::filesystem::is_regular_file(pConfig)) { - std::cerr << str(boost::format("UNL_DEFAULT not regular file: %s") % theConfig.UNL_DEFAULT) << std::endl; + std::cerr << str(boost::format(VALIDATORS_FILE_NAME " not regular file: %s") % pConfig) << std::endl; return false; } - std::ifstream ifsDefault(theConfig.UNL_DEFAULT.native().c_str(), std::ios::in); + std::ifstream ifsDefault(pConfig.native().c_str(), std::ios::in); if (!ifsDefault) { - std::cerr << str(boost::format("Failed to open: %s") % theConfig.UNL_DEFAULT) << std::endl; + std::cerr << str(boost::format(VALIDATORS_FILE_NAME " failed to open: %s") % pConfig) << std::endl; return false; } @@ -1524,14 +1527,14 @@ bool UniqueNodeList::nodeLoad() if (ifsDefault.bad()) { - std::cerr << str(boost::format("Failed to read: %s") % theConfig.UNL_DEFAULT) << std::endl; + std::cerr << str(boost::format("Failed to read: %s") % pConfig) << std::endl; return false; } - nodeDefault(strValidators, theConfig.UNL_DEFAULT.string()); + nodeProcess("local", strValidators, pConfig.string()); - std::cerr << str(boost::format("Processing: %s") % theConfig.UNL_DEFAULT) << std::endl; + std::cerr << str(boost::format("Processing: %s") % pConfig) << std::endl; return true; } @@ -1542,7 +1545,7 @@ void UniqueNodeList::validatorsResponse(const boost::system::error_code& err, st if (!err) { - nodeDefault(strResponse, VALIDATORS_SITE); + nodeProcess("network", strResponse, theConfig.VALIDATORS_SITE); } else { @@ -1554,7 +1557,7 @@ void UniqueNodeList::nodeNetwork() { HttpsClient::httpsGet( theApp->getIOService(), - VALIDATORS_SITE, + theConfig.VALIDATORS_SITE, 443, VALIDATORS_FILE_PATH, VALIDATORS_FILE_BYTES_MAX, @@ -1581,23 +1584,45 @@ void UniqueNodeList::nodeBootstrap() bool bLoaded = iDomains || iNodes; - if (!bLoaded && !theConfig.UNL_DEFAULT.empty()) + // Always merge in the file specified in the config. + if (!theConfig.UNL_DEFAULT.empty()) { - std::cerr << "Bootstrapping UNL: loading from file." << std::endl; + std::cerr << "Bootstrapping UNL: loading from unl_default." << std::endl; - bLoaded = nodeLoad(); + bLoaded = nodeLoad(theConfig.UNL_DEFAULT); + } + + // If never loaded anything try the current directory. + if (!bLoaded && theConfig.UNL_DEFAULT.empty()) + { + std::cerr << "Bootstrapping UNL: loading from '" VALIDATORS_FILE_NAME "'." << std::endl; + + bLoaded = nodeLoad(VALIDATORS_FILE_NAME); + } + + // Always load from newcoind.cfg + if (!theConfig.VALIDATORS.empty()) + { + NewcoinAddress naInvalid; // Don't want a referrer on added entries. + + std::cerr << "Bootstrapping UNL: loading from " CONFIG_FILE_NAME "." << std::endl; + + if (processValidators("local", CONFIG_FILE_NAME, naInvalid, vsConfig, &theConfig.VALIDATORS)) + bLoaded = true; } if (!bLoaded) { - std::cerr << "Bootstrapping UNL: loading from " VALIDATORS_SITE "." << std::endl; + std::cerr << "Bootstrapping UNL: loading from " << theConfig.VALIDATORS_SITE << "." << std::endl; + nodeNetwork(); } } // Process a validators.txt. +// --> strSite: source of validators // --> strValidators: contents of a validators.txt -void UniqueNodeList::nodeDefault(const std::string& strValidators, const std::string& strSource) { +void UniqueNodeList::nodeProcess(const std::string& strSite, const std::string& strValidators, const std::string& strSource) { section secValidators = ParseSection(strValidators, true); section::mapped_type* pmtEntries = sectionEntries(secValidators, SECTION_VALIDATORS); @@ -1606,7 +1631,7 @@ void UniqueNodeList::nodeDefault(const std::string& strValidators, const std::st NewcoinAddress naInvalid; // Don't want a referrer on added entries. // YYY Unspecified might be bootstrap or rpc command - processValidators("unspecified", strSource, naInvalid, vsValidator, pmtEntries); + processValidators(strSite, strSource, naInvalid, vsValidator, pmtEntries); } else { diff --git a/src/UniqueNodeList.h b/src/UniqueNodeList.h index 8ef9b88f0..2149c313f 100644 --- a/src/UniqueNodeList.h +++ b/src/UniqueNodeList.h @@ -32,10 +32,11 @@ class UniqueNodeList { public: typedef enum { + vsConfig = 'C', // newcoind.cfg vsManual = 'M', + vsReferral = 'R', vsValidator = 'V', // validators.txt vsWeb = 'W', - vsReferral = 'R', } validatorSource; typedef long score; @@ -121,7 +122,7 @@ private: 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, validatorSource vsWhy, section::mapped_type* pmtVecStrValidators); + int processValidators(const std::string& strSite, const std::string& strValidatorsSrc, const NewcoinAddress& naNodePublic, validatorSource vsWhy, section::mapped_type* pmtVecStrValidators); void processFile(const std::string strDomain, const NewcoinAddress& naNodePublic, section secSite); @@ -132,7 +133,7 @@ private: void setSeedNodes(const seedNode& snSource, bool bNext); void validatorsResponse(const boost::system::error_code& err, std::string strResponse); - void nodeDefault(const std::string& strValidators, const std::string& strSource); + void nodeProcess(const std::string& strSite, const std::string& strValidators, const std::string& strSource); public: UniqueNodeList(boost::asio::io_service& io_service); @@ -151,7 +152,7 @@ public: bool nodeInUNL(const NewcoinAddress& naNodePublic); void nodeBootstrap(); - bool nodeLoad(); + bool nodeLoad(boost::filesystem::path pConfig); void nodeNetwork(); Json::Value getUnlJson();