Alphabet class for base58 conversions, Validators work

This commit is contained in:
Vinnie Falco
2013-10-03 18:29:30 -07:00
parent 7d089561c3
commit 66a272debd
21 changed files with 468 additions and 220 deletions

View File

@@ -269,15 +269,19 @@ public:
//
void addStatic (Source* source)
{
m_journal.info << "Addding static source '" << source->name() << "'";
m_journal.info << "Addding static " << source->name();
ScopedPointer <Source> object (source);
Source::Result result (object->fetch (m_journal));
Source::Result result;
object->fetch (result, m_journal);
if (result.success)
{
SharedState::Access state (m_state);
merge (result.list, source, state);
std::size_t const numAdded (
merge (result.list, source, state));
m_journal.info << "Added " << numAdded
<< " trusted validators from " << source->name();
}
else
{
@@ -289,7 +293,7 @@ public:
//
void add (Source* source)
{
m_journal.info << "Adding source '" << source->name() << "'";
m_journal.info << "Adding " << source->name();
{
SharedState::Access state (m_state);
@@ -303,13 +307,13 @@ public:
// Add each entry in the list to the map, incrementing the
// reference count if it already exists, and updating fields.
//
void merge (Array <Source::Info> const& list,
std::size_t merge (std::vector <Source::Info> const& list,
Source* source, SharedState::Access& state)
{
std::size_t numAdded (0);
for (std::size_t i = 0; i < list.size (); ++i)
{
Source::Info const& info (list.getReference (i));
Source::Info const& info (list [i]);
std::pair <MapType::iterator, bool> result (
state->map.emplace (info.publicKey, Validator ()));
Validator& validatorInfo (result.first->second);
@@ -322,20 +326,19 @@ public:
}
}
m_journal.info << "Added " << numAdded
<< " trusted validators from '" << source->name() << "'";
return numAdded;
}
// Decrement the reference count of each item in the list
// in the map.
//
void remove (Array <Source::Info> const& list,
std::size_t remove (std::vector <Source::Info> const& list,
Source* source, SharedState::Access& state)
{
std::size_t numRemoved (0);
for (std::size_t i = 0; i < list.size (); ++i)
{
Source::Info const& info (list.getReference (i));
Source::Info const& info (list [i]);
MapType::iterator iter (state->map.find (info.publicKey));
bassert (iter != state->map.end ());
Validator& validatorInfo (iter->second);
@@ -348,8 +351,7 @@ public:
}
}
m_journal.info << "Removed " << numRemoved
<< " trusted validators from '" << source->name() << "'";
return numRemoved;
}
//----------------------------------------------------------------------
@@ -410,9 +412,12 @@ public:
/** Perform a fetch on the source. */
void fetch (SourceDesc& desc)
{
m_journal.info << "fetch " << desc.source->name();
Source* const source (desc.source);
Source::Result result (desc.source->fetch (m_journal));
m_journal.info << "fetch " << source->name();
Source::Result result;
source->fetch (result, m_journal);
// Reset fetch timer for the source.
desc.whenToFetch = Time::getCurrentTime () +
@@ -423,13 +428,22 @@ public:
SharedState::Access state (m_state);
// Add the new source info to the map
merge (result.list, desc.source, state);
std::size_t const numAdded (
merge (result.list, source, state));
// Swap lists
desc.result.swapWith (result);
// Remove the old source info from the map
remove (result.list, desc.source, state);
std::size_t const numRemoved (
remove (result.list, source, state));
if (numAdded > numRemoved)
m_journal.info << "Added " << (numAdded - numRemoved) <<
" trusted validators from " << source->name();
else if (numRemoved > numAdded)
m_journal.info << "Removed " << (numRemoved - numAdded) <<
" trusted validators from " << source->name();
// See if we need to rebuild
checkChosen ();

View File

@@ -188,14 +188,19 @@ public:
void addStrings (String name, StringArray const& stringArray)
{
addStaticSource (SourceStrings::New (
name, stringArray));
if (stringArray.size() > 0)
{
addStaticSource (SourceStrings::New (name, stringArray));
}
else
{
m_journal.debug << "Static source '" << name << "' is empty.";
}
}
void addFile (File const& file)
{
//addStaticSource (SourceFile::New (file));
addSource (SourceFile::New (file));
addStaticSource (SourceFile::New (file));
}
void addURL (URL const& url)

View File

@@ -30,7 +30,7 @@ void Source::Result::swapWith (Result& other)
{
std::swap (success, other.success);
std::swap (message, other.message);
list.swapWith (other.list);
list.swap (other.list);
}
}

View File

@@ -36,7 +36,7 @@ public:
String name ()
{
return "File :'" + m_file.getFullPathName () + "'";
return "File: '" + m_file.getFullPathName () + "'";
}
String uniqueID ()
@@ -48,11 +48,9 @@ public:
{
return m_file.getFullPathName ();
}
Result fetch (Journal journal)
void fetch (Result& result, Journal journal)
{
Result result;
int64 const fileSize (m_file.getSize ());
if (fileSize != 0)
@@ -68,6 +66,8 @@ public:
if (amountRead == fileSize)
{
Utilities::ParseResultLine lineFunction (result, journal);
Utilities::processLines (buffer.begin(), buffer.end(), lineFunction);
}
}
else
@@ -79,8 +79,6 @@ public:
{
// file doesn't exist
}
return result;
}
private:

View File

@@ -51,11 +51,9 @@ public:
return String::empty;
}
Result fetch (Journal journal)
void fetch (Result& result, Journal journal)
{
Result result;
result.list.ensureStorageAllocated (m_strings.size ());
result.list.reserve (m_strings.size ());
for (int i = 0; i < m_strings.size (); ++i)
{
@@ -65,7 +63,6 @@ public:
result.success = result.list.size () > 0;
result.expirationTime = Time::getCurrentTime () + RelativeTime::hours (24);
return result;
}
private:

View File

@@ -49,17 +49,22 @@ public:
return m_url.full();
}
Result fetch (Journal journal)
void fetch (Result& result, Journal journal)
{
Result result;
ScopedPointer <HTTPClientBase> client (HTTPClientBase::New ());
HTTPClientBase::result_type httpResult (client->get (m_url));
if (httpResult.first == 0)
{
//Logger::outputDebugString (httpResult.second->toString ());
#if 0
journal.debug << std::endl << httpResult.second->toString ();
journal.debug << std::endl << httpResult.second->body().to_string();
#endif
Utilities::ParseResultLine lineFunction (result, journal);
std::string const s (httpResult.second->body().to_string());
Utilities::processLines (s.begin(), s.end(), lineFunction);
}
else
{
@@ -67,8 +72,6 @@ public:
"HTTP GET to " << m_url.full().toStdString() <<
" failed: '" << httpResult.first.message () << "'";
}
return result;
}
private:
@@ -80,10 +83,7 @@ private:
SourceURL* SourceURL::New (
URL const& url)
{
ScopedPointer <SourceURL> object (
new SourceURLImp (url));
return object.release ();
return new SourceURLImp (url);
}
}

View File

@@ -36,6 +36,9 @@ Error StoreSqdb::open (File const& file)
if (!error)
error = init ();
if (!error)
error = update ();
return error;
}
@@ -116,20 +119,16 @@ void StoreSqdb::update (SourceDesc& desc, bool updateFetchResults)
if (! error && updateFetchResults)
{
// Delete the previous data set
{
sqdb::statement st = (m_session.prepare <<
"DELETE FROM ValidatorsSourceInfo WHERE "
" sourceID = ?; "
,sqdb::use (sourceID)
);
st.execute_and_fetch (error);
}
m_session.once (error) <<
"DELETE FROM ValidatorsSourceInfo WHERE "
" sourceID = ?; "
,sqdb::use (sourceID)
;
// Insert the new data set
if (! error)
{
std::string publicKey;
std::string publicKeyString;
String label;
sqdb::statement st = (m_session.prepare <<
@@ -141,15 +140,15 @@ void StoreSqdb::update (SourceDesc& desc, bool updateFetchResults)
" ?, ?, ? "
");"
,sqdb::use (sourceID)
,sqdb::use (publicKey)
,sqdb::use (publicKeyString)
,sqdb::use (label)
);
Array <Source::Info>& list (desc.result.list);
std::vector <Source::Info>& list (desc.result.list);
for (std::size_t i = 0; ! error && i < list.size(); ++i)
{
Source::Info& info (list.getReference(i));
publicKey = Utilities::publicKeyToString (info.publicKey);
Source::Info& info (list [i]);
publicKeyString = info.publicKey.to_string ();
label = list[i].label;
st.execute_and_fetch (error);
}
@@ -255,11 +254,11 @@ void StoreSqdb::selectList (SourceDesc& desc)
bassert (desc.result.list.size() == 0);
// Pre-allocate some storage
desc.result.list.ensureStorageAllocated (count);
desc.result.list.reserve (count);
// Prepare the select
{
std::string publicKey;
std::string publicKeyString;
std::string label;
sqdb::statement st = (m_session.prepare <<
"SELECT "
@@ -267,7 +266,7 @@ void StoreSqdb::selectList (SourceDesc& desc)
" label "
"FROM ValidatorsSourceInfo WHERE "
" sourceID = ? "
,sqdb::into (publicKey)
,sqdb::into (publicKeyString)
,sqdb::into (label)
,sqdb::use (sourceID)
);
@@ -278,9 +277,20 @@ void StoreSqdb::selectList (SourceDesc& desc)
do
{
Source::Info info;
info.publicKey = Utilities::stringToPublicKey (publicKey);
info.label = label;
desc.result.list.add (info);
std::pair <RipplePublicKey, bool> result (
RipplePublicKey::from_string (publicKeyString));
if (result.second)
{
bassert (result.first.to_string() == publicKeyString);
info.publicKey = result.first;
info.label = label;
desc.result.list.push_back (info);
}
else
{
m_journal.error << "Invalid public key '" <<
publicKeyString << "' found in database";
}
}
while (st.fetch (error));
}
@@ -294,6 +304,81 @@ void StoreSqdb::selectList (SourceDesc& desc)
//--------------------------------------------------------------------------
// Update the database for the current schema
Error StoreSqdb::update ()
{
Error error;
sqdb::transaction tr (m_session);
// Get the version from the database
int version (0);
if (! error)
{
m_session.once (error) <<
"SELECT "
" version "
"FROM SchemaVersion WHERE "
" name = 'Validators' "
,sqdb::into (version)
;
if (! m_session.got_data ())
{
// pre-dates the "SchemaVersion" table
version = 0;
}
}
if (! error && version != currentSchemaVersion)
{
m_journal.info << "Updating old database version " << version;
}
// Update database based on version
if (! error && version < 1)
{
// Delete all the old data since its likely wrong
m_session.once (error) <<
"DELETE FROM ValidatorsSource";
if (! error)
{
m_session.once (error) <<
"DELETE FROM ValidatorsSourceInfo";
}
}
// Update the version to the current version
if (! error)
{
int const version (currentSchemaVersion);
m_session.once (error) <<
"INSERT OR REPLACE INTO SchemaVersion ( "
" name, "
" version "
") VALUES ( "
" 'Validators', ? "
"); "
,sqdb::use (version)
;
}
if (! error)
{
error = tr.commit();
}
if (error)
{
tr.rollback ();
report (error, __FILE__, __LINE__);
}
return error;
}
Error StoreSqdb::init ()
{
Error error;
@@ -342,6 +427,23 @@ Error StoreSqdb::init ()
;
}
if (! error)
{
// This table maps component names like "Validators" to their
// corresponding schema version number. This method allows us
// to keep all logic data in one database, or each in its own
// database, or in any grouping of databases, while still being
// able to let an individual component know what version of its
// schema it is opening.
//
m_session.once (error) <<
"CREATE TABLE IF NOT EXISTS SchemaVersion ( "
" name TEXT PRIMARY KEY, "
" version INTEGER"
");"
;
}
if (! error)
{
error = tr.commit();

View File

@@ -29,6 +29,12 @@ class StoreSqdb
, public LeakChecked <StoreSqdb>
{
public:
enum
{
// This affects the format of the data!
currentSchemaVersion = 1
};
explicit StoreSqdb (Journal journal = Journal());
~StoreSqdb ();
@@ -45,6 +51,7 @@ private:
bool select (SourceDesc& desc);
void selectList (SourceDesc& desc);
Error update ();
Error init ();
Journal m_journal;

View File

@@ -121,23 +121,19 @@ public:
return String::empty;
}
Result fetch (Journal)
void fetch (Result& result, Journal)
{
Result result;
result.success = true;
result.message = String::empty;
result.list.ensureStorageAllocated (numberOfTestValidators);
result.list.reserve (numberOfTestValidators);
for (uint32 i = m_start ; i < m_end; ++i)
{
Info info;
info.publicKey = RipplePublicKey::createFromInteger (i);
info.label = String::fromNumber (i);
result.list.add (info);
result.list.push_back (info);
}
return result;
}
String m_name;

View File

@@ -24,22 +24,25 @@ struct Utilities::Helpers
{
// Matches a validator info line.
//
static boost::regex& reInfo ()
static boost::regex const& reInfo ()
{
// e.g.
//
// n9KorY8QtTdRx7TVDpwnG9NvyxsDwHUKUEeDLY3AkiGncVaSXZi5 Comment Text
//
static boost::regex re (
"^" // start of line
"(?:\\h*)" // horiz-white (optional)
"([^\\h\\v]+)" // [1] non-white run
"(?:\\h*)" // horiz-white (optional)
"([^\\h\\v]*)" // [2] any text (optional)
"$" // end of line
"\\G" // end of last match (or start)
"(?:[\\v\\h]*)" // white (optional)
"([^\\h\\v]+)" // [1] non-white run
"(?:\\h*)" // horiz-white (optional)
"([^\\v]*?)" // [2] non vert-white text (optional)
"(?:\\h*)" // white run (optional)
"(?:\\v*)" // vert-white (optional)
, boost::regex::perl |
boost::regex_constants::match_flags::match_not_dot_null
//"(?:\\')" // buffer boundary
, boost::regex::perl
//| boost::regex_constants::match_flags::match_not_dot_newline
);
return re;
@@ -47,7 +50,7 @@ struct Utilities::Helpers
// Matches a comment or whitespace line.
//
static boost::regex& reComment ()
static boost::regex const& reComment ()
{
// e.g.
//
@@ -87,23 +90,18 @@ bool Utilities::parseInfoLine (
RippleAddress deprecatedPublicKey;
// VFALCO NOTE These bool return values are poorlydocumented
//
if (deprecatedPublicKey.setSeedGeneric (encodedKey))
{
// expected a domain or public key but got a generic seed?
// log?
}
else if (deprecatedPublicKey.setNodePublic (encodedKey))
if (deprecatedPublicKey.setNodePublic (encodedKey))
{
// We got a public key.
RipplePublicKey publicKey (deprecatedPublicKey);
info.label = commentText;
info.publicKey = publicKey;
success = true;
}
else
{
// Some other junk.
// log?
journal.error << "Invalid RipplePublicKey: '" << encodedKey << "'";
}
}
else if (boost::regex_match (line, match, Helpers::reComment ()))
@@ -113,54 +111,9 @@ bool Utilities::parseInfoLine (
else
{
// Log a warning about a parsing error
journal.error << "Invalid Validators source line:" << std::endl << line;
}
#if 0
static boost::regex reReferral ("\\`\\s*(\\S+)(?:\\s+(.+))?\\s*\\'");
if (!boost::regex_match (strReferral, smMatch, reReferral))
{
WriteLog (lsWARNING, UniqueNodeList) << str (boost::format ("Bad validator: syntax error: %s: %s") % strSite % strReferral);
}
else
{
std::string strRefered = smMatch[1];
std::string strComment = smMatch[2];
RippleAddress naValidator;
if (naValidator.setSeedGeneric (strRefered))
{
WriteLog (lsWARNING, UniqueNodeList) << str (boost::format ("Bad validator: domain or public key required: %s %s") % strRefered % strComment);
}
else if (naValidator.setNodePublic (strRefered))
{
// A public key.
// XXX Schedule for CAS lookup.
nodeAddPublic (naValidator, vsWhy, strComment);
WriteLog (lsINFO, UniqueNodeList) << str (boost::format ("Node Public: %s %s") % strRefered % strComment);
if (naNodePublic.isValid ())
vstrValues.push_back (str (boost::format ("('%s',%d,'%s')") % strNodePublic % iValues % naValidator.humanNodePublic ()));
iValues++;
}
else
{
// A domain: need to look it up.
nodeAddDomain (strRefered, vsWhy, strComment);
WriteLog (lsINFO, UniqueNodeList) << str (boost::format ("Node Domain: %s %s") % strRefered % strComment);
if (naNodePublic.isValid ())
vstrValues.push_back (str (boost::format ("('%s',%d,%s)") % strNodePublic % iValues % sqlEscape (strRefered)));
iValues++;
}
}
#endif
return success;
}
@@ -171,15 +124,13 @@ void Utilities::parseResultLine (
std::string const& line,
Journal journal)
{
bool success = false;
Source::Info info;
if (! success)
bool success = parseInfoLine (info, line, journal);
if (success)
{
Source::Info info;
success = parseInfoLine (info, line, journal);
if (success)
result.list.add (info);
result.list.push_back (info);
result.success = true;
}
}
@@ -249,19 +200,6 @@ Time Utilities::stringToTime (String s)
return Time (0);
}
std::string Utilities::publicKeyToString (RipplePublicKey const& publicKey)
{
std::string s (RipplePublicKey::size, ' ');
std::copy (publicKey.cbegin(), publicKey.cend(), s.begin());
return s;
}
RipplePublicKey Utilities::stringToPublicKey (std::string const& s)
{
bassert (s.size() == RipplePublicKey::size);
return RipplePublicKey ();
}
//------------------------------------------------------------------------------
}

View File

@@ -23,31 +23,93 @@
namespace ripple {
namespace Validators {
/** Common code for Validators classes.
*/
/** Common code for Validators classes. */
class Utilities
{
public:
typedef std::vector <std::string> Strings;
#if 0
/** Parse a ConstBufferSequence of newline delimited text into strings.
This works incrementally.
*/
template <typename ConstBufferSequence>
static void parseLines (Strings& lines, ConstBufferSequence const& buffers)
/** A suitable LineFunction for parsing items into a fetch result. */
class ParseResultLine
{
for (typename ConstBufferSequence::const_iterator iter = buffers.begin ();
iter != buffers.end (); ++iter)
parserLines (lines, *iter);
}
public:
ParseResultLine (Source::Result& result, Journal journal)
: m_result (&result)
, m_journal (journal)
{ }
/** Turn a linear buffer of newline delimited text into strings.
This can be called incrementally, i.e. successive calls with
multiple buffer segments.
template <typename BidirectionalIterator>
void operator() (BidirectionalIterator first, BidirectionalIterator last)
{
std::string s (first, last);
Utilities::parseResultLine (*m_result, s, m_journal);
}
private:
Source::Result* m_result;
Journal m_journal;
};
/** UnaryPredicate for breaking up lines.
This returns `true` for the first non-vertical whitespace character that
follows a vertical whitespace character.
*/
static void parseLines (Strings& lines, char const* buf, std::size_t bytes);
#endif
class FollowingVerticalWhite
{
public:
FollowingVerticalWhite ()
: m_gotWhite (false)
{
}
template <typename CharT>
static bool isVerticalWhitespace (CharT c)
{
return c == '\r' || c == '\n';
}
template <typename CharT>
bool operator() (CharT c)
{
if (isVerticalWhitespace (c))
{
m_gotWhite = true;
return false;
}
else if (m_gotWhite)
{
m_gotWhite = false;
return true;
}
return false;
}
private:
bool m_gotWhite;
};
/** Call LineFunction for each newline-separated line in the input.
LineFunction will be called with this signature:
@code
void LineFunction (BidirectionalIterator first, BidirectionalIterator last)
@endcode
Where first and last mark the beginning and ending of the line.
The last line in the input may or may not contain the trailing newline.
*/
template <typename BidirectionalIterator, typename LineFunction>
static void processLines (BidirectionalIterator first,
BidirectionalIterator last, LineFunction f)
{
for (;;)
{
BidirectionalIterator split (std::find_if (
first, last, FollowingVerticalWhite ()));
f (first, split);
if (split == last)
break;
first = split;
}
}
/** Parse a string into the Source::Result.
Invalid or comment lines will be skipped.
@@ -67,10 +129,6 @@ public:
static String timeToString (Time const& t);
static Time stringToTime (String s);
// conversion between RipplePublicKey and String
static std::string publicKeyToString (RipplePublicKey const& publicKey);
static RipplePublicKey stringToPublicKey (std::string const& s);
struct Helpers;
/** Parse a string into a Source::Info.