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

@@ -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.
*/
struct ValidatorInfo
{
// VFALCO TODO magic number argh!!!
// This type should be located elsewhere.
//
typedef UnsignedInteger <33> PublicKey;
PublicKey publicKey;
String friendlyName;
String organizationType;
String jurisdicton;
};
//------------------------------------------------------------------------------
/** 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.
*/
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;
};
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)
: m_startIndex (startIndex)
, m_numEntries (numEntries)
// Produces validators for unit tests.
class TestSource : public Validators::Source
{
}
void fetch (Array <ValidatorInfo>& results)
{
for (unsigned int publicKeyIndex = m_startIndex;
publicKeyIndex < m_startIndex + m_numEntries;
++publicKeyIndex)
public:
TestSource (unsigned int startIndex, unsigned int endIndex)
: m_startIndex (startIndex)
, m_endIndex (endIndex)
{
ValidatorInfo info;
info.publicKey = Validator::PublicKey::createFromInteger (publicKeyIndex);
results.add (info);
}
}
private:
unsigned const m_startIndex;
int const m_numEntries;
};
Array <Validator::Info> fetch ()
{
Array <Validator::Info> results;
//------------------------------------------------------------------------------
for (unsigned int publicKeyIndex = m_startIndex; publicKeyIndex <= m_endIndex; ++publicKeyIndex)
{
Validator::Info info;
class ValidatorListTests : public UnitTest
{
public:
ValidatorListTests () : UnitTest ("ValidatorList", "ripple")
info.publicKey = Validator::PublicKey::createFromInteger (publicKeyIndex);
results.add (info);
}
return results;
}
private:
unsigned int const m_startIndex;
unsigned int const m_endIndex;
};
//--------------------------------------------------------------------------
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);