Validator work

This commit is contained in:
Vinnie Falco
2013-07-26 20:58:43 -07:00
parent adad62aed8
commit 9112c6e80a
12 changed files with 278 additions and 284 deletions

View File

@@ -1465,7 +1465,7 @@
<ClInclude Include="..\..\modules\ripple_core\validator\ripple_TrustedUriValidatorSource.h" />
<ClInclude Include="..\..\modules\ripple_core\validator\ripple_Validator.h" />
<ClInclude Include="..\..\modules\ripple_core\validator\ripple_ValidatorList.h" />
<ClInclude Include="..\..\modules\ripple_core\validator\ripple_ValidatorListImp.h" />
<ClInclude Include="..\..\modules\ripple_core\validator\ripple_ValidatorImp.h" />
<ClInclude Include="..\..\modules\ripple_core\validator\ripple_Validators.h" />
<ClInclude Include="..\..\modules\ripple_data\crypto\ripple_Base58.h" />
<ClInclude Include="..\..\modules\ripple_data\crypto\ripple_Base58Data.h" />

View File

@@ -1428,9 +1428,6 @@
<ClInclude Include="..\..\modules\ripple_core\validator\ripple_StringsValidatorSource.h">
<Filter>[1] Ripple\ripple_core\validator</Filter>
</ClInclude>
<ClInclude Include="..\..\modules\ripple_core\validator\ripple_ValidatorListImp.h">
<Filter>[1] Ripple\ripple_core\validator</Filter>
</ClInclude>
<ClInclude Include="..\..\modules\ripple_app\node\ripple_HyperLevelDBBackendFactory.h">
<Filter>[1] Ripple\ripple_app\node</Filter>
</ClInclude>
@@ -1659,6 +1656,9 @@
<ClInclude Include="..\..\modules\ripple_app\tx\WalletAddTransactor.h">
<Filter>[1] Ripple\ripple_app\tx</Filter>
</ClInclude>
<ClInclude Include="..\..\modules\ripple_core\validator\ripple_ValidatorImp.h">
<Filter>[1] Ripple\ripple_core\validator</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<CustomBuild Include="..\..\modules\ripple_data\protocol\ripple.proto">

View File

@@ -2,31 +2,46 @@
RIPPLE TODO
--------------------------------------------------------------------------------
Items marked '*' can be handled by third parties.
Vinnie's Short List (Changes day to day)
Vinnie's List: Changes day to day, descending priority
(Items marked '*' can be handled by others.)
* Make everyone check GitHub Issues every day
- Finish unit tests and code for Validators
- Do something about the throw() reporting weaknesses:
* Make sure all Sconstruct and .pro builds have debug symbols in release
* Replace all throw with beast::Throw()
(Only in ripple sources, not in Subtrees/, protobuf, or websocket)
- Add file and line capabilities to beast::Throw()
- Allow beast::Throw to be hooked for logging
- Add stack trace capability to beast::Throw() diagnostics via the hook
(use the existing beast::SystemStats::getStackBacktrace())
- Implement getStackBacktrace for BEAST_BSD targets
- Use the result of the beast UnitTests as the return code for main()
* Document the command line options for the beast unit test framework
- Tidy up all the loose files at the root of the repository
- What the heck is up with site_scons/site_tools/protoc.py?
- Review boost::asio wrappers and consolidation of network code in ripple_net
- Refactor Section code into ConfigFile
- Improved Mutex to track deadlocks
- Finish unit tests and code for Validators
- Import beast::db and use it in SQliteBackend
- Work on KeyvaDB
--------------------------------------------------------------------------------
- Use static creation member functions instead of endless constructor
variations in base_uint, uint256, and family.
- Take away the "I" prefix from abstract interface classes, in both the class
* Take away the "I" prefix from abstract interface classes, in both the class
name and the file name. It is messing up sorting in the IDE. Use "Imp" or
suffix for implementations.
- Raise the warning level and fix everything
* Restyle all the macros in ripple_ConfigSection.h
* Replace all throw with beast::Throw
Only in the ripple sources, not in Subtrees/ or protobuf or websocket
- Clean up the remainder of src/
- Replace home-made database wrappers with beast::sqdb
- Use static creation member functions instead of endless constructor
variations in base_uint, uint256, and family.
- Raise the warning level and fix everything
- Replace base_uint and uintXXX with UnsignedInteger
* Need to specialize UnsignedInteger to work efficiently with 4 and 8 byte
@@ -42,17 +57,10 @@ Vinnie's Short List (Changes day to day)
- Rename RPCHandler to CallHandler
- Move everything in src/cpp/ripple into ripple_app and sort them into
subdirectories within the module as per the project filters.
* Make sure there are no pending commits from David
- See if UniqueNodeList is really used, and if its not used remove it. If
only some small part of it is used, then delete the rest. David says
that it is broken anyway.
- Roll a simple wrapper for sqlite relational stuff like loading the UNL
Completely hide the specifics of SQLite and/or beast::db
- Tidy up convenience functions in RPC.h
- Maybe rename RPCServer to RPCClientServicer

View File

@@ -32,7 +32,7 @@ namespace ripple
#include "functional/ripple_LoadMonitor.cpp"
#include "validator/ripple_Validator.cpp"
#include "validator/ripple_ValidatorListImp.h" // private
#include "validator/ripple_ValidatorImp.h" // private
#include "validator/ripple_Validators.cpp"
#include "validator/ripple_StringsValidatorSource.cpp"
#include "validator/ripple_TrustedUriValidatorSource.cpp"

View File

@@ -15,8 +15,9 @@ public:
{
}
void fetch (Array <ValidatorInfo>& results)
Array <Validator::Info> fetch ()
{
return Array <Validator::Info> ();
}
private:

View File

@@ -7,7 +7,7 @@
class TrustedUriValidatorSourceImp : public TrustedUriValidatorSource
{
public:
TrustedUriValidatorSourceImp (String const url)
explicit TrustedUriValidatorSourceImp (String const url)
: m_url (url)
{
}
@@ -16,8 +16,9 @@ public:
{
}
void fetch (Array <ValidatorInfo>& results)
Array <Validator::Info> fetch ()
{
return Array <Validator::Info> ();
}
private:

View File

@@ -7,46 +7,102 @@
#ifndef RIPPLE_VALIDATOR_H_INCLUDED
#define RIPPLE_VALIDATOR_H_INCLUDED
/** Fixed information on a validator.
//------------------------------------------------------------------------------
/** Identifies a validator.
A validator signs ledgers and participates in the consensus process.
These are kept in a map so we can retrieve a unique Validator object
given the public key in the ValidatorInfo.
*/
struct ValidatorInfo
class Validator : public SharedObject
{
public:
/** Fixed information on a validator.
This describes a validator.
*/
struct Info
{
struct Compare
{
static int compareElements (Info const& lhs, Info const& rhs)
{
int result;
if (lhs.publicKey < rhs.publicKey)
result = -1;
else if (lhs.publicKey > rhs.publicKey)
result = 1;
else
result = 0;
return result;
}
};
// VFALCO TODO magic number argh!!!
// This type should be located elsewhere.
//
typedef UnsignedInteger <33> PublicKey;
PublicKey publicKey;
String friendlyName;
String organizationType;
String jurisdicton;
};
//String friendlyName;
//String organizationType;
//String jurisdicton;
};
/** Identifies a validator.
A validator signs ledgers and participates in the consensus process.
*/
class Validator : public SharedObject
{
public:
typedef SharedObjectPtr <Validator> Ptr;
typedef ValidatorInfo::PublicKey PublicKey;
typedef Info::PublicKey PublicKey;
//--------------------------------------------------------------------------
/** A list of Validator that comes from a source of validators.
Sources include trusted URIs, or a local file. The list may be
signed.
*/
class List : public SharedObject
{
public:
typedef SharedObjectPtr <List> Ptr;
explicit List (SharedObjectArray <Validator>& list)
{
m_list.swapWithArray (list);
}
~List ()
{
}
/** Retrieve the number of items. */
int size () const noexcept
{
return m_list.size ();
}
/** Retrieve an item by index. */
Validator::Ptr operator[] (int index) const
{
return m_list.getObjectPointer (index);
}
private:
SharedObjectArray <Validator> m_list;
};
class ListImp;
//--------------------------------------------------------------------------
public:
explicit Validator (PublicKey const& publicKey);
//Validator (Validator const&);
PublicKey const& getPublicKey () const { return m_publicKey; }
// not thread safe
void incrementWeight () { ++m_weight; }
private:
ValidatorInfo m_info;
PublicKey m_publicKey;
int m_weight;
PublicKey const m_publicKey;
};
#endif

View File

@@ -0,0 +1,12 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
#ifndef RIPPLE_VALIDATORLISTIMP_H_INCLUDED
#define RIPPLE_VALIDATORLISTIMP_H_INCLUDED
// This is a private header
#endif

View File

@@ -7,28 +7,4 @@
#ifndef RIPPLE_VALIDATORLIST_H_INCLUDED
#define RIPPLE_VALIDATORLIST_H_INCLUDED
/** A list of Validator that comes from a source of validators.
Sources include trusted URIs, or a local file.
The list may be signed.
*/
class ValidatorList : public SharedObject
{
public:
typedef SharedObjectPtr <ValidatorList> Ptr;
virtual ~ValidatorList () { }
/** Retrieve the number of items.
*/
virtual int size () const noexcept = 0;
virtual Validator::Ptr operator[] (int index) = 0;
/** Add a validator to the list.
*/
virtual void add (Validator::Ptr validator) = 0;
};
#endif

View File

@@ -1,44 +0,0 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
#ifndef RIPPLE_VALIDATORLISTIMP_H_INCLUDED
#define RIPPLE_VALIDATORLISTIMP_H_INCLUDED
// This is a private header
/** Private implementation of ValidatorList.
*/
class ValidatorListImp : public ValidatorList
{
public:
ValidatorListImp ()
{
}
~ValidatorListImp ()
{
}
int size () const noexcept
{
return m_list.size ();
}
Validator::Ptr operator[] (int index)
{
return m_list.getObjectPointer (index);
}
void add (Validator::Ptr validator)
{
m_list.add (validator);
}
private:
SharedObjectArray <Validator> m_list;
};
#endif

View File

@@ -36,6 +36,7 @@ class ValidatorsImp
: public Validators
, private ThreadWithCallQueue::EntryPoints
, private DeadlineTimer::Listener
, LeakChecked <ValidatorsImp>
{
public:
// Tunable constants
@@ -47,7 +48,7 @@ public:
,secondsBetweenFetches = hoursBetweenFetches * 60 * 60
// Wake up every hour to check source times
,timerGranularity = 60 * 60
,secondsPerUpdate = 60 * 60
// This tunes the preallocated arrays
,expectedNumberOfResults = 1000
@@ -55,24 +56,7 @@ public:
//--------------------------------------------------------------------------
struct ValidatorInfoCompare
{
static int compareElements (ValidatorInfo const& lhs, ValidatorInfo const& rhs)
{
int result;
if (lhs.publicKey < rhs.publicKey)
result = -1;
else if (lhs.publicKey > rhs.publicKey)
result = 1;
else
result = 0;
return result;
}
};
struct SourceInfo
struct SourceInfo : LeakChecked <SourceInfo>
{
enum Status
{
@@ -88,53 +72,57 @@ public:
{
}
Source* source;
ScopedPointer <Source> const source;
Status status;
Time whenToFetch;
int numberOfFailures; // of fetch()
// The number of times a fetch has failed.
int numberOfFailures;
Validator::List::Ptr lastFetchResults;
};
// This is what comes back from a source
typedef Array <SourceInfo> SourceInfoArray;
typedef Array <ValidatorInfo> ValidatorInfoArray;
typedef OwnedArray <SourceInfo> SourceInfoArray;
// The result of performing a fetch
struct FetchResult
{
#if 0
// This is what comes back from the fetch
ValidatorInfoArray updatedList;
Validator::ListImp::Ptr updatedList;
// The original list before the fetch
SharedObjectArray <Validator> oldList;
Validator::List oldList;
// The new list after the fetch
SharedObjectArray <Validator> newList;
Validator::List newList;
// The list of validators that were added
SharedObjectArray <Validator> addedList;
Validator::List addedList;
// The list of validators that were removed
SharedObjectArray <Validator> removedList;
Validator::List removedList;
#endif
FetchResult ()
{
/*
updatedList.ensureStorageAllocated (expectedNumberOfResults);
oldList.ensureStorageAllocated (expectedNumberOfResults);
newList.ensureStorageAllocated (expectedNumberOfResults);
addedList.ensureStorageAllocated (expectedNumberOfResults);
removedList.ensureStorageAllocated (expectedNumberOfResults);
*/
}
void clear ()
{
updatedList.clearQuick ();
/*
//updatedList.clearQuick ();
oldList.clear ();
newList.clear ();
addedList.clear ();
removedList.clear ();
*/
}
};
@@ -145,18 +133,21 @@ public:
//
class Logic
{
private:
HashMap <Validator::PublicKey,
Validator::Ptr,
Validator::PublicKey::HashFunction> m_map;
SourceInfoArray m_sourceInfo;
public:
Logic ()
: m_knownValidators (new ValidatorListImp)
, m_chosenValidators (new ValidatorListImp)
{
}
void addSource (Source* source)
{
m_sources.add (source);
m_sourceInfo.add (SourceInfo (source));
m_sourceInfo.add (new SourceInfo (source));
}
SourceInfoArray& getSources ()
@@ -164,43 +155,35 @@ public:
return m_sourceInfo;
}
void processValidatorInfo (ValidatorInfoArray& fetchResults)
void sortValidatorInfo (Array <Validator::Info>& arrayToSort)
{
}
void sortValidatorInfo (ValidatorInfoArray& arrayToSort)
{
ValidatorInfoArray sorted;
Array <Validator::Info> sorted;
sorted.ensureStorageAllocated (arrayToSort.size ());
for (int i = 0; i < arrayToSort.size (); ++i)
{
ValidatorInfoCompare compare;
Validator::Info::Compare compare;
sorted.addSorted (compare, arrayToSort [i]);
}
arrayToSort.swapWithArray (sorted);
}
void fetchSource (SourceInfo& sourceInfo)
{
}
// Given the old list and the new list for a source, this
// computes which validators were added or removed, and
// updates some statistics. It also produces the new list.
//
void processFetch (FetchResult* pFetchResult,
ValidatorInfoArray& oldList,
ValidatorInfoArray& newList)
Validator::List& oldList,
Validator::List& newList)
{
#if 0
ValidatorsImp::FetchResult& fetchResult (*pFetchResult);
// First sort both arrays.
//
ValidatorInfoCompare compare;
Validator::Info::Compare compare;
oldList.sort (compare, true);
newList.sort (compare, true);
@@ -221,7 +204,8 @@ public:
}
else
{
int const result = ValidatorInfoCompare::compareElements (oldList [i], newList [i]);
int const result = Validator::Info::Compare::compareElements (
oldList [i], newList [i]);
if (result < 0)
{
@@ -239,13 +223,59 @@ public:
}
}
}
#endif
}
// Produces an array of references to validators given the validator info.
Validator::List::Ptr createListFromInfo (Array <Validator::Info> const& info)
{
SharedObjectArray <Validator> items;
items.ensureStorageAllocated (info.size ());
for (int i = 0; i < info.size (); ++i)
{
Validator::PublicKey const& key (info [i].publicKey);
Validator::Ptr validator = m_map [key];
if (validator == nullptr)
{
validator = new Validator (key);
m_map [key] = validator;
}
items.add (validator);
}
return new Validator::List (items);
}
// Fetch the validators from a source and process the result
//
void fetchSource (SourceInfo& sourceInfo)
{
Array <Validator::Info> fetchedInfo = sourceInfo.source->fetch ();
if (fetchedInfo.size () != 0)
{
sourceInfo.status = SourceInfo::statusFetched;
sourceInfo.whenToFetch = Time::getCurrentTime () +
RelativeTime (hoursBetweenFetches * 60.0 * 60.0);
//processFetchedInfo (fetchedInfo);
}
else
{
// Failed to fetch
// Don't update fetch time
sourceInfo.status = SourceInfo::statusFailed;
sourceInfo.numberOfFailures++;
}
}
private:
OwnedArray <Source> m_sources;
SourceInfoArray m_sourceInfo;
ValidatorList::Ptr m_knownValidators;
ValidatorList::Ptr m_chosenValidators;
};
//--------------------------------------------------------------------------
@@ -280,51 +310,21 @@ public:
m_thread.interrupt ();
}
// Goes through all the sources and refreshes them as needed
// Fetch sources whose deadline timers have arrived.
//
bool scanSources ()
{
bool interrupted = false;
Time currentTime = Time::getCurrentTime ();
ValidatorInfoArray fetchResults;
fetchResults.ensureStorageAllocated (1000);
SourceInfoArray sourceInfoArray (m_logic.getSources ());
// Find a source that needs to be processed
//
for (int i = 0; i < sourceInfoArray.size (); ++i)
for (int i = 0; i < m_logic.getSources ().size (); ++i)
{
SourceInfo& sourceInfo (sourceInfoArray.getReference (i));
SourceInfo& sourceInfo (*m_logic.getSources ()[i]);
Time const currentTime = Time::getCurrentTime ();
// See if we need to refresh its list
//
if (currentTime <= sourceInfo.whenToFetch)
{
sourceInfo.source->fetch (fetchResults);
currentTime = Time::getCurrentTime ();
if (fetchResults.size () != 0)
{
sourceInfo.status = SourceInfo::statusFetched;
sourceInfo.whenToFetch = currentTime + RelativeTime (hoursBetweenFetches * 60.0 * 60.0);
m_logic.processValidatorInfo (fetchResults);
//m_listener->onValidatorsChosen (chosenValidators);
}
else
{
// Failed to fetch
// Don't update fetch time
sourceInfo.status = SourceInfo::statusFailed;
sourceInfo.numberOfFailures++;
}
fetchResults.clearQuick ();
m_logic.fetchSource (sourceInfo);
}
interrupted = m_thread.interruptionPoint ();
@@ -338,7 +338,7 @@ public:
void threadInit ()
{
m_timer.setRecurringExpiration (timerGranularity);
m_timer.setRecurringExpiration (secondsPerUpdate);
}
void threadExit ()
@@ -368,95 +368,77 @@ Validators* Validators::New (Listener* listener)
//------------------------------------------------------------------------------
// Produces validators for unit tests.
class TestValidatorSource : public Validators::Source
class ValidatorsTests : public UnitTest
{
public:
TestValidatorSource (unsigned int startIndex, int numEntries)
// Produces validators for unit tests.
class TestSource : public Validators::Source
{
public:
TestSource (unsigned int startIndex, unsigned int endIndex)
: m_startIndex (startIndex)
, m_numEntries (numEntries)
, m_endIndex (endIndex)
{
}
void fetch (Array <ValidatorInfo>& results)
Array <Validator::Info> fetch ()
{
for (unsigned int publicKeyIndex = m_startIndex;
publicKeyIndex < m_startIndex + m_numEntries;
++publicKeyIndex)
Array <Validator::Info> results;
for (unsigned int publicKeyIndex = m_startIndex; publicKeyIndex <= m_endIndex; ++publicKeyIndex)
{
ValidatorInfo info;
Validator::Info info;
info.publicKey = Validator::PublicKey::createFromInteger (publicKeyIndex);
results.add (info);
}
return results;
}
private:
unsigned const m_startIndex;
int const m_numEntries;
};
private:
unsigned int const m_startIndex;
unsigned int const m_endIndex;
};
//------------------------------------------------------------------------------
//--------------------------------------------------------------------------
class ValidatorListTests : public UnitTest
{
public:
ValidatorListTests () : UnitTest ("ValidatorList", "ripple")
ValidatorsTests () : UnitTest ("Validators", "ripple")
{
}
// Check public key routines
void publicKeyTest ()
{
beginTest ("compare");
ValidatorInfo::PublicKey one (ValidatorInfo::PublicKey::createFromInteger (1U));
ValidatorInfo::PublicKey two (ValidatorInfo::PublicKey::createFromInteger (2U));
expect (one < two, "should be less");
expect (two > one, "should be greater");
}
// Verify the test fetching
void fetchTest ()
{
beginTest ("fetch");
ValidatorsImp::ValidatorInfoArray results;
TestValidatorSource (0, 32).fetch (results);
expect (results.size () == 32, "size should be 32");
}
// Check logic for comparing a source's fetch results
void processFetchTest ()
void processTest ()
{
beginTest ("process fetch");
beginTest ("process");
ValidatorsImp::ValidatorInfoArray oldList;
TestValidatorSource (1, 2).fetch (oldList);
expect (oldList.size () == 2, "size should be 2");
{
Array <Validator::Info> results = TestSource (1, 32).fetch ();
expect (results.size () == 32);
}
ValidatorsImp::ValidatorInfoArray newList;
TestValidatorSource (2, 2).fetch (newList);
expect (newList.size () == 2, "size should be 2");
{
Array <Validator::Info> oldList = TestSource (1, 2).fetch ();
expect (oldList.size () == 2);
ValidatorsImp::FetchResult fetchResult;
Array <Validator::Info> newList = TestSource (2, 3).fetch ();
expect (newList.size () == 2);
ValidatorsImp::Logic ().processFetch (&fetchResult, oldList, newList);
ValidatorsImp::Logic logic;
Validator::List::Ptr list = logic.createListFromInfo (newList);
//ValidatorsImp::FetchResult fetchResult;
//ValidatorsImp::Logic ().processFetch (&fetchResult, oldList, newList);
}
}
void runTest ()
{
publicKeyTest ();
fetchTest ();
processFetchTest ();
processTest ();
}
};
static ValidatorListTests validatorListTests;
static ValidatorsTests validatorsTests;

View File

@@ -33,19 +33,21 @@ public:
This call blocks.
*/
virtual void fetch (Array <ValidatorInfo>& results) = 0;
virtual Array <Validator::Info> fetch () =0;
};
public:
//--------------------------------------------------------------------------
/** Receive event notifications on Validators operations.
*/
class Listener
{
public:
virtual void onValidatorsChosen (ValidatorList::Ptr list) { }
virtual void onValidatorsChosen (Validator::List::Ptr list) { }
};
public:
//--------------------------------------------------------------------------
/** Create a new Validators object.
*/
static Validators* New (Listener* listener);