diff --git a/src/BeastConfig.h b/src/BeastConfig.h index 05dc73cdc..50ee90542 100644 --- a/src/BeastConfig.h +++ b/src/BeastConfig.h @@ -171,7 +171,7 @@ // is being written. // #ifndef RIPPLE_USE_NEW_VALIDATORS -#define RIPPLE_USE_NEW_VALIDATORS 0 +#define RIPPLE_USE_NEW_VALIDATORS 1 #endif // Turning this on makes the Application object get destroyed, diff --git a/src/beast/beast/utility/Journal.h b/src/beast/beast/utility/Journal.h index 25161f7fa..e262d98a4 100644 --- a/src/beast/beast/utility/Journal.h +++ b/src/beast/beast/utility/Journal.h @@ -38,12 +38,15 @@ public: /** Severity level of the message. */ enum Severity { - kTrace, + kLowestSeverity = 0, + kTrace = kLowestSeverity, kDebug, kInfo, kWarning, kError, - kFatal + kFatal, + + kDisabled }; //-------------------------------------------------------------------------- @@ -57,15 +60,16 @@ public: /** Write text to the sink at the specified severity. */ virtual void write (Severity severity, std::string const& text) = 0; - /** Returns `true` if text at the passed severity produces output. - The default implementation always returns `true`. - */ - virtual bool active (Severity); + /** Returns `true` if text at the passed severity produces output. */ + virtual bool active (Severity severity) = 0; - /** Returns `true` if text at the severity goes to the Output window. */ - virtual bool console (); + /** Returns `true` if a message is also written to the Output Window (MSVC). */ + virtual bool console () = 0; + /** Set the minimum severity this sink will report. */ virtual void set_severity (Severity severity) = 0; + + /** Set whether messages are also written to the Output Window (MSVC). */ virtual void set_console (bool to_console) = 0; }; @@ -122,19 +126,26 @@ public: /** Construct a stream which produces no logging output. */ Stream (); + /** Construct a stream that writes to the Sink at the given Severity. */ Stream (Sink& sink, Severity severity); + + /** Construct or copy another Stream. */ + /** @{ */ Stream (Stream const& other); Stream& operator= (Stream const& other); + /** @} */ - /** Returns `true` if the sink logs messages at the severity of this stream. */ - bool active() const; - - /** Returns `true` if the stream also logs messages to the Output window. */ - bool console() const; - + /** Returns the Sink that this Stream writes to. */ Sink& sink() const; + + /** Returns the Severity of messages this Stream reports. */ Severity severity() const; + /** Returns `true` if sink logs anything at this stream's severity. */ + bool active() const; + + /** Output stream support. */ + /** @{ */ ScopedStream operator<< (std::ostream& manip (std::ostream&)) const; template @@ -142,6 +153,7 @@ public: { return ScopedStream (*this, t); } + /** @} */ private: Sink* m_sink; @@ -155,16 +167,14 @@ public: Journal (Journal const& other); ~Journal (); + /** Returns the Sink associated with this Journal. */ + Sink& sink() const; + /** Returns a stream for this sink, with the specified severity. */ Stream stream (Severity severity) const; - Sink& sink() const; - - /** Returns `true` if the sink logs messages at that severity. */ - /** @{ */ + /** Returns `true` if any message would be logged at this severity level. */ bool active (Severity severity) const; - bool console () const; - /** @} */ /** Convenience sink streams for each severity level. */ Stream const trace; diff --git a/src/beast/beast/utility/impl/Journal.cpp b/src/beast/beast/utility/impl/Journal.cpp index 5435b83a0..868e5ad64 100644 --- a/src/beast/beast/utility/impl/Journal.cpp +++ b/src/beast/beast/utility/impl/Journal.cpp @@ -22,15 +22,7 @@ namespace beast { -bool Journal::Sink::active (Severity) -{ - return true; -} - -bool Journal::Sink::console () -{ - return false; -} +//------------------------------------------------------------------------------ // A Sink that does nothing. class NullJournalSink : public Journal::Sink @@ -45,7 +37,7 @@ public: return false; } - bool console (Journal::Severity) + bool console () { return false; } @@ -94,11 +86,6 @@ Journal::ScopedStream::~ScopedStream () { if (m_sink.active (m_severity)) m_sink.write (m_severity, m_ostream.str()); - - #if BEAST_MSVC - if (m_sink.console () && beast_isRunningUnderDebugger ()) - Logger::outputDebugString (m_ostream.str()); - #endif } } @@ -116,7 +103,7 @@ std::ostringstream& Journal::ScopedStream::ostream () const Journal::Stream::Stream () : m_sink (&getNullSink ()) - , m_severity (kFatal) + , m_severity (kDisabled) { } @@ -124,6 +111,7 @@ Journal::Stream::Stream (Sink& sink, Severity severity) : m_sink (&sink) , m_severity (severity) { + bassert (severity != kDisabled); } Journal::Stream::Stream (Stream const& other) @@ -132,16 +120,6 @@ Journal::Stream::Stream (Stream const& other) { } -bool Journal::Stream::active () const -{ - return m_sink->active (m_severity); -} - -bool Journal::Stream::console() const -{ - return m_sink->console (); -} - Journal::Sink& Journal::Stream::sink () const { return *m_sink; @@ -152,6 +130,11 @@ Journal::Severity Journal::Stream::severity () const return m_severity; } +bool Journal::Stream::active () const +{ + return m_sink->active (m_severity); +} + Journal::Stream& Journal::Stream::operator= (Stream const& other) { m_sink = other.m_sink; @@ -203,25 +186,20 @@ Journal::~Journal () { } -Journal::Stream Journal::stream (Severity severity) const -{ - return Stream (*m_sink, severity); -} - Journal::Sink& Journal::sink() const { return *m_sink; } -/** Returns `true` if the sink logs messages at that severity. */ +Journal::Stream Journal::stream (Severity severity) const +{ + return Stream (*m_sink, severity); +} + bool Journal::active (Severity severity) const { + bassert (severity != kDisabled); return m_sink->active (severity); } -bool Journal::console () const -{ - return m_sink->console (); -} - } diff --git a/src/ripple/validators/api/Manager.h b/src/ripple/validators/api/Manager.h index 8494c45e7..1c92bfdf2 100644 --- a/src/ripple/validators/api/Manager.h +++ b/src/ripple/validators/api/Manager.h @@ -17,7 +17,6 @@ */ //============================================================================== - #ifndef RIPPLE_VALIDATORS_MANAGER_H_INCLUDED #define RIPPLE_VALIDATORS_MANAGER_H_INCLUDED @@ -25,56 +24,55 @@ namespace ripple { namespace Validators { /** Maintains the list of chosen validators. - The algorithm for acquiring, building, and calculating metadata on the list of chosen validators is critical to the health of the network. - All operations are performed asynchronously on an internal thread. */ class Manager : public RPC::Service { public: /** Create a new Manager object. + @param parent The parent Stoppable. + @param journal Where to send log output. */ static Manager* New (Stoppable& parent, Journal journal); /** Destroy the object. - - Any pending source fetch operations are aborted. - - There may be some listener calls made before the - destructor returns. + Any pending source fetch operations are aborted. This will block + until any pending database I/O has completed and the thread has + stopped. */ virtual ~Manager () { } - /** Add a static source of validators from a string array. */ + /** Add a static source of validators. + The validators added using these methods will always be chosen when + constructing the UNL regardless of statistics. The fetch operation + is performed asynchronously, so this call returns immediately. A + failed fetch (depending on the source) is not retried. The caller + loses ownership of any dynamic objects. + Thread safety: + Can be called from any thread. + */ /** @{ */ virtual void addStrings (String name, std::vector const& strings) = 0; virtual void addStrings (String name, StringArray const& stringArray) = 0; + virtual void addFile (File const& file) = 0; + virtual void addStaticSource (Source* source) = 0; /** @} */ - /** Add a static source of validators from a text file. */ - virtual void addFile (File const& file) = 0; - - /** Add a static source of validators. - The Source is called to fetch once and the results are kept - permanently. The fetch is performed asynchronously, this call - returns immediately. If the fetch fails, it is not reattempted. - The caller loses ownership of the object. + /** Add a live source of validators from a trusted URL. + The URL will be contacted periodically to update the list. The fetch + operation is performed asynchronously, this call doesn't block. Thread safety: Can be called from any thread. */ - virtual void addStaticSource (Source* source) = 0; - - /** Add a live source of validators from a trusted URL. - The URL will be contacted periodically to update the list. - */ virtual void addURL (URL const& url) = 0; /** Add a live source of validators. - The caller loses ownership of the object. + The caller loses ownership of the object. The fetch is performed + asynchronously, this call doesn't block. Thread safety: Can be called from any thread. */ @@ -82,12 +80,8 @@ public: //-------------------------------------------------------------------------- - // Trusted Validators - //virtual bool isPublicKeyTrusted (RipplePublicKey const& publicKey) = 0; - //-------------------------------------------------------------------------- - /** Called when a validation with a proper signature is received. */ virtual void receiveValidation (ReceivedValidation const& rv) = 0; diff --git a/src/ripple/validators/impl/Manager.cpp b/src/ripple/validators/impl/Manager.cpp index 57c183e28..9abd666c5 100644 --- a/src/ripple/validators/impl/Manager.cpp +++ b/src/ripple/validators/impl/Manager.cpp @@ -17,84 +17,82 @@ */ //============================================================================== -/* +/** ChosenValidators (formerly known as UNL) -Information to track: + Motivation: -- Percentage of validations that the validator has signed -- Number of validations the validator signed that never got accepted + To protect the integrity of the shared ledger data structure, Validators + independently sign LedgerHash objects with their RipplePublicKey. These + signed Validations are propagated through the peer to peer network so + that other nodes may inspect them. Every peer and client on the network + gains confidence in a ledger and its associated chain of previous ledgers + by maintaining a suitably sized list of Validator public keys that it + trusts. + + The most important factors in choosing Validators for a ChosenValidators + list (the name we will use to designate such a list) are the following: + + - That different Validators are not controlled by one entity + - That each Validator participates in a majority of ledgers + - That a Validator does not sign ledgers which fail consensus + + This module maintains ChosenValidators list. The list is built from a set + of independent Source objects, which may come from the configuration file, + a separate file, a URL from some trusted domain, or from the network itself. + + In order that rippled administrators may publish their ChosenValidators + list at a URL on a trusted domain that they own, this module compiles + statistics on ledgers signed by validators and stores them in a database. + From this database reports and alerts may be generated so that up-to-date + information about the health of the set of ChosenValidators is always + availabile. + + In addition to the automated statistics provided by the module, it is + expected that organizations and meta-organizations will form from + stakeholders such as gateways who publish their own lists and provide + "best practices" to further refine the quality of validators placed into + ChosenValidators list. -- Target number for Chosen -- Pseudo-randomly choose a subset from Chosen + ---------------------------------------------------------------------------- + Unorganized Notes: + David: + Maybe OC should have a URL that you can query to get the latest list of URI's + for OC-approved organzations that publish lists of validators. The server and + client can ship with that master trust URL and also the list of URI's at the + time it's released, in case for some reason it can't pull from OC. That would + make the default installation safe even against major changes in the + organizations that publish validator lists. + The difference is that if an organization that provides lists of validators + goes rogue, administrators don't have to act. + TODO: + Write up from end-user perspective on the deployment and administration + of this feature, on the wiki. "DRAFT" or "PROPOSE" to mark it as provisional. + Template: https://ripple.com/wiki/Federation_protocol + - What to do if you're a publisher of ValidatorList + - What to do if you're a rippled administrator + - Overview of how ChosenValidators works -Goal: + Goals: + Make default configuration of rippled secure. + * Ship with TrustedUriList + * Also have a preset RankedValidators + Eliminate administrative burden of maintaining + Produce the ChosenValidators list. + Allow quantitative analysis of network health. - Provide the listener with a ValidatorList. - - This forms the UNL - -Task: - - fetch ValidatorInfo array from a source - - - We have the old one and the new one, compute the following: - - * unchanged validators list - * new validators list - * removed validators list - - - From the unchanged / new / removed, figure out what to do. - -Two important questions: - -- Are there any validators in my ChosenValidators that I dont want - * For example, they have dropped off all the trusted lists - -- Do I have enough? - --------------------------------------------------------------------------------- -ChosenValidators --------------------------------------------------------------------------------- - -David: - Maybe OC should have a URL that you can query to get the latest list of URI's - for OC-approved organzations that publish lists of validators. The server and - client can ship with that master trust URL and also the list of URI's at the - time it's released, in case for some reason it can't pull from OC. That would - make the default installation safe even against major changes in the - organizations that publish validator lists. - - The difference is that if an organization that provides lists of validators - goes rogue, administrators don't have to act. - -TODO: - Write up from end-user perspective on the deployment and administration - of this feature, on the wiki. "DRAFT" or "PROPOSE" to mark it as provisional. - Template: https://ripple.com/wiki/Federation_protocol - - What to do if you're a publisher of ValidatorList - - What to do if you're a rippled administrator - - Overview of how ChosenValidators works - -Goals: - Make default configuration of rippled secure. - * Ship with TrustedUriList - * Also have a preset RankedValidators - Eliminate administrative burden of maintaining - Produce the ChosenValidators list. - Allow quantitative analysis of network health. - -What determines that a validator is good? - - Are they present (i.e. sending validations) - - Are they on the consensus ledger - - What percentage of consensus rounds do they participate in - - Are they stalling consensus - * Measurements of constructive/destructive behavior is - calculated in units of percentage of ledgers for which - the behavior is measured. + What determines that a validator is good? + - Are they present (i.e. sending validations) + - Are they on the consensus ledger + - What percentage of consensus rounds do they participate in + - Are they stalling consensus + * Measurements of constructive/destructive behavior is + calculated in units of percentage of ledgers for which + the behavior is measured. */ namespace ripple { @@ -128,7 +126,13 @@ public: , m_checkTimer (this) , m_checkSources (true) { - m_journal.sink().set_console (true); +#if BEAST_MSVC + if (beast_isRunningUnderDebugger()) + { + m_journal.sink().set_console (true); + m_journal.sink().set_severity (Journal::kLowestSeverity); + } +#endif } ~ManagerImp () diff --git a/src/ripple_basics/log/LogJournal.h b/src/ripple_basics/log/LogJournal.h index 25b5e989d..9a3f85c37 100644 --- a/src/ripple_basics/log/LogJournal.h +++ b/src/ripple_basics/log/LogJournal.h @@ -17,7 +17,6 @@ */ //============================================================================== - #ifndef RIPPLE_BASICS_LOGJOURNAL_H_INCLUDED #define RIPPLE_BASICS_LOGJOURNAL_H_INCLUDED @@ -37,13 +36,22 @@ public: public: PartitionSink () : m_partition (LogPartition::get ()) - , m_console (false) + , m_severity (Journal::kLowestSeverity) + , m_to_console (false) { } void write (Journal::Severity severity, std::string const& text) { - LogSink::get()->write (text, convertSeverity (severity), m_partition.getName()); + std::string output; + LogSeverity const logSeverity (convertSeverity (severity)); + LogSink::get()->format (output, text, logSeverity, + m_partition.getName()); + LogSink::get()->write (output, logSeverity); + #if BEAST_MSVC + if (m_to_console && beast_isRunningUnderDebugger ()) + Logger::outputDebugString (output.c_str()); + #endif } bool active (Journal::Severity severity) @@ -53,24 +61,24 @@ public: bool console() { - return m_console; + return m_to_console; } void set_severity (Journal::Severity severity) { - // VFALCO TODO Per-partition severity levels - bassertfalse; + LogSeverity const logSeverity (convertSeverity (severity)); + m_partition.setMinimumSeverity (logSeverity); } void set_console (bool to_console) { - m_console = to_console; + m_to_console = to_console; } private: - LogPartition const& m_partition; + LogPartition& m_partition; Journal::Severity m_severity; - bool m_console; + bool m_to_console; }; //-------------------------------------------------------------------------- diff --git a/src/ripple_basics/log/LogPartition.cpp b/src/ripple_basics/log/LogPartition.cpp index 8c3425d69..7a67d13fb 100644 --- a/src/ripple_basics/log/LogPartition.cpp +++ b/src/ripple_basics/log/LogPartition.cpp @@ -47,6 +47,11 @@ std::vector< std::pair > LogPartition::getSeverities ( //------------------------------------------------------------------------------ +void LogPartition::setMinimumSeverity (LogSeverity severity) +{ + mMinSeverity = severity; +} + bool LogPartition::setSeverity (const std::string& partition, LogSeverity severity) { for (LogPartition* p = headLog; p != NULL; p = p->mNextLog) diff --git a/src/ripple_basics/log/LogPartition.h b/src/ripple_basics/log/LogPartition.h index 4fb83a6b3..bb33b8732 100644 --- a/src/ripple_basics/log/LogPartition.h +++ b/src/ripple_basics/log/LogPartition.h @@ -21,17 +21,17 @@ #ifndef RIPPLE_BASICS_LOGPARTITION_H_INCLUDED #define RIPPLE_BASICS_LOGPARTITION_H_INCLUDED -class LogPartition // : public List ::Node +class LogPartition { public: - LogPartition (const char* partitionName); + explicit LogPartition (const char* partitionName); /** Retrieve the LogPartition associated with an object. Each LogPartition is a singleton. */ template - static LogPartition const& get () + static LogPartition& get () { struct LogPartitionType : LogPartition { @@ -53,6 +53,8 @@ public: return mName; } + void setMinimumSeverity (LogSeverity severity); + static bool setSeverity (const std::string& partition, LogSeverity severity); static void setSeverity (LogSeverity severity); static std::vector< std::pair > getSeverities (); diff --git a/src/ripple_basics/log/LogSink.cpp b/src/ripple_basics/log/LogSink.cpp index b210cbc9f..dabb694b2 100644 --- a/src/ripple_basics/log/LogSink.cpp +++ b/src/ripple_basics/log/LogSink.cpp @@ -17,7 +17,6 @@ */ //============================================================================== - LogSink::LogSink () : m_mutex ("Log", __FILE__, __LINE__) , m_minSeverity (lsINFO) @@ -71,47 +70,59 @@ std::string LogSink::rotateLog () } } +void LogSink::format ( + std::string& output, + std::string const& message, + LogSeverity severity, + std::string const& partitionName) +{ + output.reserve (message.size() + partitionName.size() + 100); + + output = boost::posix_time::to_simple_string ( + boost::posix_time::second_clock::universal_time ()); + + output += " "; + if (! partitionName.empty ()) + output += partitionName + ":"; + + switch (severity) + { + case lsTRACE: output += "TRC "; break; + case lsDEBUG: output += "DBG "; break; + case lsINFO: output += "NFO "; break; + case lsWARNING: output += "WRN "; break; + case lsERROR: output += "ERR "; break; + default: + bassertfalse; + case lsFATAL: output += "FTL "; + break; + } + + output += replaceFirstSecretWithAsterisks (message); + + if (output.size() > maximumMessageCharacters) + { + output.resize (maximumMessageCharacters - 3); + output += "..."; + } +} + void LogSink::write ( std::string const& message, LogSeverity severity, std::string const& partitionName) { - std::string text; - text.reserve (message.size() + partitionName.size() + 100); + std::string output; - text = boost::posix_time::to_simple_string ( - boost::posix_time::second_clock::universal_time ()); + format (output, message, severity, partitionName); - text += " "; - if (! partitionName.empty ()) - text += partitionName + ":"; + write (output, severity); +} - switch (severity) - { - case lsTRACE: text += "TRC "; break; - case lsDEBUG: text += "DBG "; break; - case lsINFO: text += "NFO "; break; - case lsWARNING: text += "WRN "; break; - case lsERROR: text += "ERR "; break; - default: - bassertfalse; - case lsFATAL: text += "FTL "; - break; - } - - text += replaceFirstSecretWithAsterisks (message); - - if (text.size() > maximumMessageCharacters) - { - text.resize (maximumMessageCharacters - 3); - text += "..."; - } - - { - ScopedLockType lock (m_mutex, __FILE__, __LINE__); - - write (text, severity >= getMinSeverity(), lock); - } +void LogSink::write (std::string const& output, LogSeverity severity) +{ + ScopedLockType lock (m_mutex, __FILE__, __LINE__); + write (output, severity >= getMinSeverity(), lock); } void LogSink::write (std::string const& text) @@ -121,37 +132,13 @@ void LogSink::write (std::string const& text) write (text, true, lock); } -void LogSink::write (StringArray const& strings) -{ - ScopedLockType lock (m_mutex, __FILE__, __LINE__); - - for (int i = 0; i < strings.size (); ++i) - write (strings [i].toStdString (), true, lock); - -} - void LogSink::write (std::string const& line, bool toStdErr, ScopedLockType&) { // Does nothing if not open. m_logFile.writeln (line); if (toStdErr) - { -#if 0 -#if BEAST_MSVC - if (beast_isRunningUnderDebugger ()) - { - // Send it to the attached debugger's Output window - // - Logger::outputDebugString (line); - } - else -#endif -#endif - { - std::cerr << line << std::endl; - } - } + std::cerr << line << std::endl; } //------------------------------------------------------------------------------ diff --git a/src/ripple_basics/log/LogSink.h b/src/ripple_basics/log/LogSink.h index e6909f181..de60288f1 100644 --- a/src/ripple_basics/log/LogSink.h +++ b/src/ripple_basics/log/LogSink.h @@ -17,7 +17,6 @@ */ //============================================================================== - #ifndef RIPPLE_BASICS_LOGSINK_H_INCLUDED #define RIPPLE_BASICS_LOGSINK_H_INCLUDED @@ -31,7 +30,10 @@ public: /** Returns the minimum severity required for also writing to stderr. */ LogSeverity getMinSeverity (); - /** Sets the minimum severity required for also writing to stderr. */ + /** Sets the minimum severity required for also writing to stderr. + If 'all' is true this will set the minimum reporting severity for + all partitions. + */ void setMinSeverity (LogSeverity, bool all); /** Sets the path to the log file. */ @@ -44,14 +46,14 @@ public: */ std::string rotateLog (); + /** Format a log message. */ + void format (std::string& output, + std::string const& message, LogSeverity severity, + std::string const& partitionName); + /** Write to log output. - - All logging eventually goes through this function. If a debugger - is attached, the string goes to the debugging console, else it goes - to the standard error output. If a log file is open, then the message - is additionally written to the open log file. - - The text should not contain a newline, it will be automatically + All logging eventually goes through these functios. + The text should not contain a final newline, it will be automatically added as needed. @note This acquires a global mutex. @@ -60,10 +62,9 @@ public: @param toStdErr `true` to also write to std::cerr */ /** @{ */ - void write (std::string const& message, - LogSeverity severity, std::string const& partitionName); + void write (std::string const& message, LogSeverity severity, std::string const& partitionName); + void write (std::string const& text, LogSeverity severity); void write (std::string const& text); - void write (StringArray const& strings); /** @} */ /** Hides secret keys from log output. */