Validators work

This commit is contained in:
Vinnie Falco
2013-09-12 15:05:26 -07:00
parent b839ae0552
commit 0d2344c9a6
26 changed files with 1337 additions and 928 deletions

View File

@@ -33,31 +33,43 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\src\ripple\testoverlay\ripple_testoverlay.cpp" />
<ClCompile Include="..\..\src\ripple\validators\impl\Validators.cpp">
<ClCompile Include="..\..\src\ripple\validators\impl\Manager.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\src\ripple\validators\impl\ValidatorSourceFile.cpp">
<ClCompile Include="..\..\src\ripple\validators\impl\Source.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\src\ripple\validators\impl\ValidatorSourceStrings.cpp">
<ClCompile Include="..\..\src\ripple\validators\impl\SourceFile.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\src\ripple\validators\impl\ValidatorSourceURL.cpp">
<ClCompile Include="..\..\src\ripple\validators\impl\SourceStrings.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\src\ripple\validators\impl\ValidatorsUtilities.cpp">
<ClCompile Include="..\..\src\ripple\validators\impl\SourceURL.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\src\ripple\validators\impl\Tests.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\src\ripple\validators\impl\Utilities.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
@@ -1409,11 +1421,17 @@
<ClInclude Include="..\..\src\ripple\testoverlay\api\SimplePayload.h" />
<ClInclude Include="..\..\src\ripple\testoverlay\api\StateBase.h" />
<ClInclude Include="..\..\src\ripple\testoverlay\ripple_testoverlay.h" />
<ClInclude Include="..\..\src\ripple\validators\api\Validators.h" />
<ClInclude Include="..\..\src\ripple\validators\impl\ValidatorSourceFile.h" />
<ClInclude Include="..\..\src\ripple\validators\impl\ValidatorSourceStrings.h" />
<ClInclude Include="..\..\src\ripple\validators\impl\ValidatorSourceURL.h" />
<ClInclude Include="..\..\src\ripple\validators\impl\ValidatorsUtilities.h" />
<ClInclude Include="..\..\src\ripple\validators\api\Source.h" />
<ClInclude Include="..\..\src\ripple\validators\api\Types.h" />
<ClInclude Include="..\..\src\ripple\validators\api\Manager.h" />
<ClInclude Include="..\..\src\ripple\validators\impl\CancelCallbacks.h" />
<ClInclude Include="..\..\src\ripple\validators\impl\ChosenList.h" />
<ClInclude Include="..\..\src\ripple\validators\impl\Logic.h" />
<ClInclude Include="..\..\src\ripple\validators\impl\SourceFile.h" />
<ClInclude Include="..\..\src\ripple\validators\impl\SourceStrings.h" />
<ClInclude Include="..\..\src\ripple\validators\impl\SourceURL.h" />
<ClInclude Include="..\..\src\ripple\validators\impl\Store.h" />
<ClInclude Include="..\..\src\ripple\validators\impl\Utilities.h" />
<ClInclude Include="..\..\src\ripple\validators\ripple_validators.h" />
<ClInclude Include="..\..\src\ripple_app\consensus\ripple_DisputedTx.h" />
<ClInclude Include="..\..\src\ripple_app\consensus\ripple_LedgerConsensus.h" />

View File

@@ -882,21 +882,6 @@
<ClCompile Include="..\..\src\ripple\validators\ripple_validators.cpp">
<Filter>[2] Ripple %28New%29\validators</Filter>
</ClCompile>
<ClCompile Include="..\..\src\ripple\validators\impl\Validators.cpp">
<Filter>[2] Ripple %28New%29\validators\impl</Filter>
</ClCompile>
<ClCompile Include="..\..\src\ripple\validators\impl\ValidatorSourceFile.cpp">
<Filter>[2] Ripple %28New%29\validators\impl</Filter>
</ClCompile>
<ClCompile Include="..\..\src\ripple\validators\impl\ValidatorSourceStrings.cpp">
<Filter>[2] Ripple %28New%29\validators\impl</Filter>
</ClCompile>
<ClCompile Include="..\..\src\ripple\validators\impl\ValidatorSourceURL.cpp">
<Filter>[2] Ripple %28New%29\validators\impl</Filter>
</ClCompile>
<ClCompile Include="..\..\src\ripple\validators\impl\ValidatorsUtilities.cpp">
<Filter>[2] Ripple %28New%29\validators\impl</Filter>
</ClCompile>
<ClCompile Include="..\..\src\ripple_app\main\FatalErrorReporter.cpp">
<Filter>[1] Ripple\ripple_app\main</Filter>
</ClCompile>
@@ -915,6 +900,27 @@
<ClCompile Include="..\..\src\ripple_basics\log\LogPartition.cpp">
<Filter>[1] Ripple\ripple_basics\log</Filter>
</ClCompile>
<ClCompile Include="..\..\src\ripple\validators\impl\Manager.cpp">
<Filter>[2] Ripple %28New%29\validators\impl</Filter>
</ClCompile>
<ClCompile Include="..\..\src\ripple\validators\impl\Source.cpp">
<Filter>[2] Ripple %28New%29\validators\impl</Filter>
</ClCompile>
<ClCompile Include="..\..\src\ripple\validators\impl\SourceFile.cpp">
<Filter>[2] Ripple %28New%29\validators\impl</Filter>
</ClCompile>
<ClCompile Include="..\..\src\ripple\validators\impl\SourceStrings.cpp">
<Filter>[2] Ripple %28New%29\validators\impl</Filter>
</ClCompile>
<ClCompile Include="..\..\src\ripple\validators\impl\SourceURL.cpp">
<Filter>[2] Ripple %28New%29\validators\impl</Filter>
</ClCompile>
<ClCompile Include="..\..\src\ripple\validators\impl\Utilities.cpp">
<Filter>[2] Ripple %28New%29\validators\impl</Filter>
</ClCompile>
<ClCompile Include="..\..\src\ripple\validators\impl\Tests.cpp">
<Filter>[2] Ripple %28New%29\validators\impl</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\src\ripple_app\ripple_app.h">
@@ -1746,21 +1752,6 @@
<ClInclude Include="..\..\src\ripple\validators\ripple_validators.h">
<Filter>[2] Ripple %28New%29\validators</Filter>
</ClInclude>
<ClInclude Include="..\..\src\ripple\validators\impl\ValidatorSourceFile.h">
<Filter>[2] Ripple %28New%29\validators\impl</Filter>
</ClInclude>
<ClInclude Include="..\..\src\ripple\validators\impl\ValidatorSourceStrings.h">
<Filter>[2] Ripple %28New%29\validators\impl</Filter>
</ClInclude>
<ClInclude Include="..\..\src\ripple\validators\impl\ValidatorSourceURL.h">
<Filter>[2] Ripple %28New%29\validators\impl</Filter>
</ClInclude>
<ClInclude Include="..\..\src\ripple\validators\impl\ValidatorsUtilities.h">
<Filter>[2] Ripple %28New%29\validators\impl</Filter>
</ClInclude>
<ClInclude Include="..\..\src\ripple\validators\api\Validators.h">
<Filter>[2] Ripple %28New%29\validators\api</Filter>
</ClInclude>
<ClInclude Include="..\..\src\ripple_app\main\FatalErrorReporter.h">
<Filter>[1] Ripple\ripple_app\main</Filter>
</ClInclude>
@@ -1785,6 +1776,39 @@
<ClInclude Include="..\..\src\ripple_basics\log\LogPartition.h">
<Filter>[1] Ripple\ripple_basics\log</Filter>
</ClInclude>
<ClInclude Include="..\..\src\ripple\validators\impl\Logic.h">
<Filter>[2] Ripple %28New%29\validators\impl</Filter>
</ClInclude>
<ClInclude Include="..\..\src\ripple\validators\api\Source.h">
<Filter>[2] Ripple %28New%29\validators\api</Filter>
</ClInclude>
<ClInclude Include="..\..\src\ripple\validators\api\Types.h">
<Filter>[2] Ripple %28New%29\validators\api</Filter>
</ClInclude>
<ClInclude Include="..\..\src\ripple\validators\api\Manager.h">
<Filter>[2] Ripple %28New%29\validators\api</Filter>
</ClInclude>
<ClInclude Include="..\..\src\ripple\validators\impl\SourceFile.h">
<Filter>[2] Ripple %28New%29\validators\impl</Filter>
</ClInclude>
<ClInclude Include="..\..\src\ripple\validators\impl\SourceStrings.h">
<Filter>[2] Ripple %28New%29\validators\impl</Filter>
</ClInclude>
<ClInclude Include="..\..\src\ripple\validators\impl\SourceURL.h">
<Filter>[2] Ripple %28New%29\validators\impl</Filter>
</ClInclude>
<ClInclude Include="..\..\src\ripple\validators\impl\Store.h">
<Filter>[2] Ripple %28New%29\validators\impl</Filter>
</ClInclude>
<ClInclude Include="..\..\src\ripple\validators\impl\Utilities.h">
<Filter>[2] Ripple %28New%29\validators\impl</Filter>
</ClInclude>
<ClInclude Include="..\..\src\ripple\validators\impl\ChosenList.h">
<Filter>[2] Ripple %28New%29\validators\impl</Filter>
</ClInclude>
<ClInclude Include="..\..\src\ripple\validators\impl\CancelCallbacks.h">
<Filter>[2] Ripple %28New%29\validators\impl</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<CustomBuild Include="..\..\src\ripple_data\protocol\ripple.proto">

View File

@@ -4,8 +4,11 @@
*/
//==============================================================================
#ifndef RIPPLE_CORE_VALIDATOR_VALIDATORS_H_INCLUDED
#define RIPPLE_CORE_VALIDATOR_VALIDATORS_H_INCLUDED
#ifndef RIPPLE_VALIDATORS_MANAGER_H_INCLUDED
#define RIPPLE_VALIDATORS_MANAGER_H_INCLUDED
namespace Validators
{
/** Maintains the list of chosen validators.
@@ -14,60 +17,12 @@
All operations are performed asynchronously on an internal thread.
*/
class Validators : public Uncopyable
class Manager : public Uncopyable
{
public:
typedef RipplePublicKeyHash KeyType;
//--------------------------------------------------------------------------
/** A source of validator descriptors. */
class Source
{
public:
/** A Source's descriptor for a Validator. */
struct Info
{
/** The unique key for this validator. */
KeyType key;
};
/** Destroy the Source.
This can be called from any thread. If the Source is busy
fetching, the destructor must block until the operation is either
canceled or complete.
/** Create a new Manager object.
*/
virtual ~Source () { }
struct CancelCallback
{
virtual bool shouldCancel () = 0;
};
/** Fetch the most recent list from the Source.
If possible, the Source should periodically poll the
CancelCallback, and abort the operation if shouldCancel
returns `true`.
This call will block.
*/
struct Result
{
Result ();
void swapWith (Result& other);
bool success;
String message;
Time expirationTime;
Array <Info> list;
};
virtual Result fetch (CancelCallback& callback) = 0;
};
//--------------------------------------------------------------------------
/** Create a new Validators object.
*/
static Validators* New ();
static Manager* New (Journal journal);
/** Destroy the object.
@@ -76,12 +31,14 @@ public:
There may be some listener calls made before the
destructor returns.
*/
virtual ~Validators () { }
virtual ~Manager () { }
/** Add a static source of validators from a string array. */
/** @{ */
virtual void addStrings (std::vector <std::string> const& strings) = 0;
virtual void addStrings (StringArray const& stringArray) = 0;
virtual void addStrings (String name,
std::vector <std::string> const& strings) = 0;
virtual void addStrings (String name,
StringArray const& stringArray) = 0;
/** @} */
/** Add a static source of validators from a text file. */
@@ -113,19 +70,15 @@ public:
// Trusted Validators
//virtual bool isPublicKeyTrusted (Validator::PublicKey const&) = 0;
//virtual bool isPublicKeyTrusted (PublicKey const& publicKey) = 0;
//--------------------------------------------------------------------------
struct ReceivedValidation
{
uint256 ledgerHash;
RipplePublicKeyHash signerPublicKeyHash;
};
/** Called when a validation with a proper signature is received.
*/
virtual void receiveValidation (ReceivedValidation const& rv) = 0;
};
}
#endif

View File

@@ -0,0 +1,60 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
#ifndef RIPPLE_VALIDATORS_SOURCE_H_INCLUDED
#define RIPPLE_VALIDATORS_SOURCE_H_INCLUDED
namespace Validators
{
/** A source of validator descriptors. */
class Source
{
public:
/** A Source's descriptor for a Validator. */
struct Info
{
/** The unique key for this validator. */
PublicKey key;
};
/** Destroy the Source.
This can be called from any thread. If the Source is busy
fetching, the destructor must block until the operation is either
canceled or complete.
*/
virtual ~Source () { }
virtual String name () = 0;
struct CancelCallback
{
virtual bool shouldCancel () = 0;
};
/** Fetch the most recent list from the Source.
If possible, the Source should periodically poll the
CancelCallback, and abort the operation if shouldCancel
returns `true`.
This call will block.
*/
struct Result
{
Result ();
void swapWith (Result& other);
bool success;
String message;
Time expirationTime;
Array <Info> list;
};
virtual Result fetch (CancelCallback& callback, Journal journal) = 0;
};
}
#endif

View File

@@ -0,0 +1,24 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
#ifndef RIPPLE_VALIDATORS_TYPES_H_INCLUDED
#define RIPPLE_VALIDATORS_TYPES_H_INCLUDED
namespace Validators
{
typedef RipplePublicKey PublicKey;
typedef RipplePublicKeyHash PublicKeyHash;
struct ReceivedValidation
{
uint256 ledgerHash;
PublicKeyHash signerPublicKeyHash;
};
}
#endif

View File

@@ -0,0 +1,54 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
#ifndef RIPPLE_VALIDATORS_CANCELCALLBACKS_H_INCLUDED
#define RIPPLE_VALIDATORS_CANCELCALLBACKS_H_INCLUDED
namespace Validators
{
// Dummy CancelCallback that does nothing
//
class NoOpCancelCallback : public Source::CancelCallback
{
public:
bool shouldCancel ()
{
return false;
}
};
//------------------------------------------------------------------------------
// CancelCallback attached to ThreadWithCallQueue
//
class ThreadCancelCallback
: public Source::CancelCallback
, public Uncopyable
{
public:
explicit ThreadCancelCallback (ThreadWithCallQueue& thread)
: m_thread (thread)
, m_interrupted (false)
{
}
bool shouldCancel ()
{
if (m_interrupted)
return true;
return m_interrupted = m_thread.interruptionPoint ();
}
private:
ThreadWithCallQueue& m_thread;
bool m_interrupted;
};
}
#endif

View File

@@ -0,0 +1,59 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
#ifndef RIPPLE_VALIDATORS_CHOSENLIST_H_INCLUDED
#define RIPPLE_VALIDATORS_CHOSENLIST_H_INCLUDED
namespace Validators
{
class ChosenList : public SharedObject
{
public:
typedef SharedPtr <ChosenList> Ptr;
struct Info
{
Info ()
{
}
};
typedef boost::unordered_map <PublicKey, Info, PublicKey::HashFunction> MapType;
ChosenList (std::size_t expectedSize = 0)
{
// Available only in recent boost versions?
//m_map.reserve (expectedSize);
}
std::size_t size () const noexcept
{
return m_map.size ();
}
void insert (PublicKey const& key, Info const& info) noexcept
{
m_map [key] = info;
}
bool containsPublicKey (PublicKey const& publicKey) const noexcept
{
return m_map.find (publicKey) != m_map.cend ();
}
bool containsPublicKeyHash (PublicKeyHash const& publicKeyHash) const noexcept
{
return false;
}
private:
MapType m_map;
};
}
#endif

View File

@@ -0,0 +1,320 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
#ifndef RIPPLE_VALIDATORS_LOGIC_H_INCLUDED
#define RIPPLE_VALIDATORS_LOGIC_H_INCLUDED
namespace Validators
{
// Tunable constants
enum
{
// We will fetch a source at this interval
hoursBetweenFetches = 24
,secondsBetweenFetches = hoursBetweenFetches * 60 * 60
// We check Source expirations on this time interval
,checkEverySeconds = 60 * 60
// This tunes the preallocated arrays
,expectedNumberOfResults = 1000
};
// Encapsulates the logic for creating the chosen validators.
// This is a separate class to facilitate the unit tests.
//
class Logic
{
public:
// Information associated with each Source
//
struct SourceDesc
{
enum
{
keysPreallocationSize = 1000
};
enum Status
{
statusNone,
statusFetched,
statusFailed
};
ScopedPointer <Source> source;
Status status;
Time whenToFetch;
int numberOfFailures;
// The result of the last fetch
Source::Result result;
//------------------------------------------------------------------
SourceDesc () noexcept
: status (statusNone)
, whenToFetch (Time::getCurrentTime ())
, numberOfFailures (0)
{
}
~SourceDesc ()
{
}
};
typedef DynamicList <SourceDesc> SourcesType;
//----------------------------------------------------------------------
// Information associated with each distinguishable validator
//
struct ValidatorInfo
{
ValidatorInfo ()
: refCount (0)
{
}
int refCount;
};
typedef boost::unordered_map <PublicKey, ValidatorInfo, PublicKey::HashFunction> MapType;
//----------------------------------------------------------------------
explicit Logic (Journal journal = Journal ())
: m_journal (journal)
, m_chosenListNeedsUpdate (false)
{
}
// Add a one-time static source.
// Fetch is called right away, this call blocks.
//
void addStaticSource (Source* source)
{
m_journal.info() << "Add static Source, " << source->name();
ScopedPointer <Source> object (source);
NoOpCancelCallback cancelCallback;
Source::Result result (object->fetch (cancelCallback, m_journal));
if (result.success)
{
addSourceInfo (result.list);
}
else
{
// VFALCO NOTE Maybe log the error and message?
}
}
// Add a live source to the list of sources.
//
void addSource (Source* source)
{
m_journal.info() << "Add Source, " << source->name();
SourceDesc& desc (*m_sources.emplace_back ());
desc.source = source;
}
// Called when we receive a validation from a peer.
//
void receiveValidation (ReceivedValidation const& rv)
{
#if 0
MapType::iterator iter (m_map.find (rv.signerPublicKeyHash));
if (iter != m_map.end ())
{
// Exists
//ValidatorInfo& validatorInfo (iter->value ());
}
else
{
// New
//ValidatorInfo& validatorInfo (m_map.insert (rv.signerPublicKeyHash));
}
#endif
}
// Add each entry in the list to the map, incrementing the
// reference count if it already exists, and updating fields.
//
void addSourceInfo (Array <Source::Info> const& list)
{
for (std::size_t i = 0; i < list.size (); ++i)
{
Source::Info const& info (list.getReference (i));
std::pair <MapType::iterator, bool> result (
m_map.emplace (info.key, ValidatorInfo ()));
ValidatorInfo& validatorInfo (result.first->second);
++validatorInfo.refCount;
if (result.second)
{
// This is a new one
markDirtyChosenList ();
}
}
}
// Decrement the reference count of each item in the list
// in the map
//
void removeSourceInfo (Array <Source::Info> const& list)
{
for (std::size_t i = 0; i < list.size (); ++i)
{
Source::Info const& info (list.getReference (i));
MapType::iterator iter (m_map.find (info.key));
bassert (iter != m_map.end ());
ValidatorInfo& validatorInfo (iter->second);
if (--validatorInfo.refCount == 0)
{
// Last reference removed
m_map.erase (iter);
markDirtyChosenList ();
}
}
}
// Fetch one source
//
void fetchSource (SourceDesc& desc, Source::CancelCallback& callback)
{
m_journal.info() << "Fetching Source, " << desc.source->name();
Source::Result result (desc.source->fetch (callback, m_journal));
if (! callback.shouldCancel ())
{
// Reset fetch timer for the source.
desc.whenToFetch = Time::getCurrentTime () +
RelativeTime (secondsBetweenFetches);
if (result.success)
{
// Add the new source info to the map
addSourceInfo (result.list);
// Swap lists
desc.result.swapWith (result);
// Remove the old source info from the map
removeSourceInfo (result.list);
// See if we need to rebuild
checkDirtyChosenList ();
// Reset failure status
desc.numberOfFailures = 0;
desc.status = SourceDesc::statusFetched;
}
else
{
++desc.numberOfFailures;
desc.status = SourceDesc::statusFailed;
}
}
}
// Check each source to see if it needs fetching.
//
void checkSources (Source::CancelCallback& callback)
{
m_journal.info() << "Checking Sources";
Time const currentTime (Time::getCurrentTime ());
for (SourcesType::iterator iter = m_sources.begin ();
! callback.shouldCancel () && iter != m_sources.end (); ++iter)
{
SourceDesc& desc (*iter);
if (desc.whenToFetch <= currentTime)
fetchSource (desc, callback);
}
}
// Signal that the Chosen List needs to be rebuilt.
//
void markDirtyChosenList ()
{
m_chosenListNeedsUpdate = true;
}
// Check the dirty state of the Chosen List, and rebuild it
// if necessary.
//
void checkDirtyChosenList ()
{
if (m_chosenListNeedsUpdate)
{
buildChosenList ();
m_chosenListNeedsUpdate = false;
}
}
// Rebuilds the Chosen List
//
void buildChosenList ()
{
ChosenList::Ptr list (new ChosenList (m_map.size ()));
for (MapType::iterator iter = m_map.begin ();
iter != m_map.end (); ++iter)
{
ChosenList::Info info;
list->insert (iter->first, info);
}
// This is thread safe
m_chosenList = list;
m_journal.debug() <<
"Rebuilt chosen list with " <<
String::fromNumber (m_chosenList->size()) << " entries";
}
// Get a reference to the chosen list.
// This is safe to call from any thread at any time.
//
ChosenList::Ptr getChosenList ()
{
return m_chosenList;
}
//----------------------------------------------------------------------
//
// Ripple interface
//
// These routines are modeled after UniqueNodeList
bool isTrustedPublicKeyHash (
PublicKeyHash const& publicKeyHash)
{
return m_chosenList->containsPublicKeyHash (publicKeyHash);
}
//
//
//----------------------------------------------------------------------
private:
Journal m_journal;
SourcesType m_sources;
MapType m_map;
bool m_chosenListNeedsUpdate;
ChosenList::Ptr m_chosenList;
};
}
#endif

View File

@@ -0,0 +1,200 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
/*
Information to track:
- Percentage of validations that the validator has signed
- Number of validations the validator signed that never got accepted
- Target number for Chosen
- Pseudo-randomly choose a subset from Chosen
Goal:
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.
*/
namespace Validators
{
class ManagerImp
: public Manager
, private ThreadWithCallQueue::EntryPoints
, private DeadlineTimer::Listener
, private LeakChecked <ManagerImp>
{
public:
explicit ManagerImp (Journal journal)
: m_logic (journal)
, m_journal (journal)
, m_thread ("Validators")
, m_checkTimer (this)
{
m_thread.start (this);
}
~ManagerImp ()
{
}
void addStrings (String name, std::vector <std::string> const& strings)
{
StringArray stringArray;
stringArray.ensureStorageAllocated (strings.size());
for (std::size_t i = 0; i < strings.size(); ++i)
stringArray.add (strings [i]);
addStrings (name, stringArray);
}
void addStrings (String name, StringArray const& stringArray)
{
addStaticSource (SourceStrings::New (
name, stringArray));
}
void addFile (File const& file)
{
addStaticSource (SourceFile::New (file));
}
void addURL (UniformResourceLocator const& url)
{
addSource (SourceURL::New (url));
}
//--------------------------------------------------------------------------
void addSource (Source* source)
{
m_thread.call (&Logic::addSource, &m_logic, source);
}
void addStaticSource (Source* source)
{
m_thread.call (&Logic::addStaticSource, &m_logic, source);
}
void receiveValidation (ReceivedValidation const& rv)
{
m_thread.call (&Logic::receiveValidation, &m_logic, rv);
}
//--------------------------------------------------------------------------
// This intermediate function is used to provide the CancelCallback
void checkSources ()
{
ThreadCancelCallback cancelCallback (m_thread);
m_logic.checkSources (cancelCallback);
}
void onDeadlineTimer (DeadlineTimer& timer)
{
if (timer == m_checkTimer)
m_thread.call (&ManagerImp::checkSources, this);
}
//--------------------------------------------------------------------------
void threadInit ()
{
m_checkTimer.setRecurringExpiration (checkEverySeconds);
}
void threadExit ()
{
}
bool threadIdle ()
{
bool interrupted = false;
return interrupted;
}
private:
Logic m_logic;
Journal m_journal;
ThreadWithCallQueue m_thread;
DeadlineTimer m_checkTimer;
};
//------------------------------------------------------------------------------
Manager* Manager::New (Journal journal)
{
return new ManagerImp (journal);
}
}

View File

@@ -0,0 +1,23 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
namespace Validators
{
Source::Result::Result ()
: success (false)
, message ("uninitialized")
{
}
void Source::Result::swapWith (Result& other)
{
std::swap (success, other.success);
std::swap (message, other.message);
list.swapWith (other.list);
}
}

View File

@@ -4,19 +4,27 @@
*/
//==============================================================================
class ValidatorSourceFileImp : public ValidatorSourceFile
namespace Validators
{
class SourceFileImp : public SourceFile
{
public:
ValidatorSourceFileImp (File const& file)
SourceFileImp (File const& file)
: m_file (file)
{
}
~ValidatorSourceFileImp ()
~SourceFileImp ()
{
}
Result fetch (CancelCallback&)
String name ()
{
return "File :'" + m_file.getFullPathName () + "'";
}
Result fetch (CancelCallback&, Journal journal)
{
Result result;
@@ -29,10 +37,12 @@ private:
//------------------------------------------------------------------------------
ValidatorSourceFile* ValidatorSourceFile::New (File const& file)
SourceFile* SourceFile::New (File const& file)
{
ScopedPointer <ValidatorSourceFile> object (
new ValidatorSourceFileImp (file));
ScopedPointer <SourceFile> object (
new SourceFileImp (file));
return object.release ();
}
}

View File

@@ -4,16 +4,21 @@
*/
//==============================================================================
#ifndef RIPPLE_CORE_VALIDATOR_VALIDATORSOURCEFILE_H_INCLUDED
#define RIPPLE_CORE_VALIDATOR_VALIDATORSOURCEFILE_H_INCLUDED
#ifndef RIPPLE_VALIDATORS_SOURCEFILE_H_INCLUDED
#define RIPPLE_VALIDATORS_SOURCEFILE_H_INCLUDED
namespace Validators
{
/** Provides validators from a text file.
Typically this will come from a local configuration file.
*/
class ValidatorSourceFile : public Validators::Source
class SourceFile : public Source
{
public:
static ValidatorSourceFile* New (File const& path);
static SourceFile* New (File const& path);
};
}
#endif

View File

@@ -4,19 +4,29 @@
*/
//==============================================================================
class ValidatorSourceStringsImp : public ValidatorSourceStrings
namespace Validators
{
class SourceStringsImp : public SourceStrings
{
public:
ValidatorSourceStringsImp (StringArray const& strings)
: m_strings (strings)
SourceStringsImp (
String name, StringArray const& strings)
: m_name (name)
, m_strings (strings)
{
}
~ValidatorSourceStringsImp ()
~SourceStringsImp ()
{
}
Result fetch (CancelCallback&)
String name ()
{
return m_name;
}
Result fetch (CancelCallback&, Journal journal)
{
Result result;
@@ -24,7 +34,8 @@ public:
for (int i = 0; i < m_strings.size (); ++i)
{
ValidatorsUtilities::parseResultLine (result, m_strings [i]);
std::string const s (m_strings [i].toStdString ());
Utilities::parseResultLine (result, s);
}
result.success = result.list.size () > 0;
@@ -33,15 +44,19 @@ public:
}
private:
String m_name;
StringArray m_strings;
};
//------------------------------------------------------------------------------
ValidatorSourceStrings* ValidatorSourceStrings::New (StringArray const& strings)
SourceStrings* SourceStrings::New (
String name, StringArray const& strings)
{
ScopedPointer <ValidatorSourceStrings> object (
new ValidatorSourceStringsImp (strings));
ScopedPointer <SourceStrings> object (
new SourceStringsImp (name, strings));
return object.release ();
}
}

View File

@@ -4,16 +4,22 @@
*/
//==============================================================================
#ifndef RIPPLE_CORE_VALIDATOR_VALIDATORSOURCESTRINGS_H_INCLUDED
#define RIPPLE_CORE_VALIDATOR_VALIDATORSOURCESTRINGS_H_INCLUDED
#ifndef RIPPLE_VALIDATORS_SOURCESTRINGS_H_INCLUDED
#define RIPPLE_VALIDATORS_SOURCESTRINGS_H_INCLUDED
namespace Validators
{
/** Provides validators from a set of Validator strings.
Typically this will come from a local configuration file.
*/
class ValidatorSourceStrings : public Validators::Source
class SourceStrings : public Source
{
public:
static ValidatorSourceStrings* New (StringArray const& strings);
static SourceStrings* New (
String name, StringArray const& strings);
};
}
#endif

View File

@@ -4,19 +4,27 @@
*/
//==============================================================================
class ValidatorSourceURLImp : public ValidatorSourceURL
namespace Validators
{
class SourceURLImp : public SourceURL
{
public:
explicit ValidatorSourceURLImp (UniformResourceLocator const& url)
explicit SourceURLImp (UniformResourceLocator const& url)
: m_url (url)
{
}
~ValidatorSourceURLImp ()
~SourceURLImp ()
{
}
Result fetch (CancelCallback&)
String name ()
{
return "URL: '" + m_url.full() + "'";
}
Result fetch (CancelCallback&, Journal journal)
{
Result result;
@@ -28,6 +36,12 @@ public:
{
//Logger::outputDebugString (httpResult.response->toString ());
}
else
{
journal.error() <<
"HTTP GET to " << m_url.full().toStdString() <<
" failed: '" << httpResult.error.message () << "'";
}
return result;
}
@@ -38,11 +52,13 @@ private:
//------------------------------------------------------------------------------
ValidatorSourceURL* ValidatorSourceURL::New (
SourceURL* SourceURL::New (
UniformResourceLocator const& url)
{
ScopedPointer <ValidatorSourceURL> object (
new ValidatorSourceURLImp (url));
ScopedPointer <SourceURL> object (
new SourceURLImp (url));
return object.release ();
}
}

View File

@@ -4,15 +4,20 @@
*/
//==============================================================================
#ifndef RIPPLE_CORE_VALIDATOR_VALIDATORSOURCETRUSTEDURL_H_INCLUDED
#define RIPPLE_CORE_VALIDATOR_VALIDATORSOURCETRUSTEDURL_H_INCLUDED
#ifndef RIPPLE_VALIDATORS_SOURCEURL_H_INCLUDED
#define RIPPLE_VALIDATORS_SOURCEURL_H_INCLUDED
namespace Validators
{
/** Provides validators from a trusted URI (e.g. HTTPS)
*/
class ValidatorSourceURL : public Validators::Source
class SourceURL : public Source
{
public:
static ValidatorSourceURL* New (UniformResourceLocator const& url);
static SourceURL* New (UniformResourceLocator const& url);
};
}
#endif

View File

@@ -0,0 +1,24 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
#ifndef RIPPLE_VALIDATORS_VALIDATORSSTORE_H_INCLUDED
#define RIPPLE_VALIDATORS_VALIDATORSSTORE_H_INCLUDED
namespace Validators
{
/** Database persistence for Validators. */
class Store
{
public:
virtual ~Store () { }
};
}
#endif

View File

@@ -0,0 +1,163 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
namespace Validators
{
class Tests : public UnitTest
{
public:
enum
{
numberOfTestValidators = 1000
};
//--------------------------------------------------------------------------
struct Payload
{
Payload ()
{
}
};
template <class Config>
class PeerLogic : public TestOverlay::PeerLogicBase <Config>
{
public:
typedef TestOverlay::PeerLogicBase <Config> Base;
typedef typename Config::Payload Payload;
typedef typename Base::Connection Connection;
typedef typename Base::Peer Peer;
typedef typename Base::Message Message;
typedef typename Config::SizeType SizeType;
explicit PeerLogic (Peer& peer)
: TestOverlay::PeerLogicBase <Config> (peer)
{
}
~PeerLogic ()
{
}
void step ()
{
if (this->peer().id () == 1)
{
if (this->peer().network().steps() == 0)
{
this->peer().network().state().increment();
this->peer().send_all (Payload (1));
}
}
}
void receive (Connection const& c, Message const& m)
{
if (this->peer().id () != 1)
{
this->peer().network().state().increment();
this->peer().send_all_if (Message (m.id(),
m.payload().withHop ()),
typename Connection::IsNotPeer (c.peer()));
}
}
};
struct Params : TestOverlay::ConfigType <
Params,
TestOverlay::StateBase,
PeerLogic
>
{
typedef TestOverlay::PremadeInitPolicy <250, 3> InitPolicy;
};
typedef Params::Network Network;
//--------------------------------------------------------------------------
struct TestSource : Source
{
TestSource (String const& name, uint32 start, uint32 end)
: m_name (name)
, m_start (start)
, m_end (end)
{
}
String name ()
{
return "Test";
}
Result fetch (CancelCallback& cancel, Journal)
{
Result result;
result.success = true;
result.message = String::empty;
result.list.ensureStorageAllocated (numberOfTestValidators);
for (uint32 i = m_start ; i < m_end; ++i)
{
Info info;
info.key = Validators::PublicKey::createFromInteger (i);
result.list.add (info);
}
return result;
}
String m_name;
std::size_t m_start;
std::size_t m_end;
};
//--------------------------------------------------------------------------
void addSources (Logic& logic)
{
#if 0
logic.addSource (new TestSource ("source 1", 0, 1000));
logic.addSource (new TestSource ("source 2", 200, 1500));
logic.addSource (new TestSource ("source 3", 500, 2000));
logic.addSource (new TestSource ("source 4", 750, 2200));
logic.addSource (new TestSource ("source 5", 1500, 3200));
#else
logic.addSource (new TestSource ("source 1", 0, 1));
#endif
}
void testLogic ()
{
beginTestCase ("logic");
Logic logic;
addSources (logic);
NoOpCancelCallback cancelCallback;
logic.checkSources (cancelCallback);
ChosenList::Ptr list (logic.getChosenList ());
pass ();
}
void runTest ()
{
testLogic ();
}
Tests () : UnitTest ("Validators", "ripple", runManual)
{
}
};
static Tests tests;
}

View File

@@ -0,0 +1,173 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
namespace Validators
{
struct Utilities::Helpers
{
// Matches a validator info line.
//
static boost::regex& 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
, boost::regex::perl |
boost::regex_constants::match_flags::match_not_dot_null
);
return re;
}
// Matches a comment or whitespace line.
//
static boost::regex& reComment ()
{
// e.g.
//
// n9KorY8QtTdRx7TVDpwnG9NvyxsDwHUKUEeDLY3AkiGncVaSXZi5 Comment Text
//
static boost::regex re (
"^" // start of line
"(?:\\h*)" // horiz-white (optional)
"(?:#.*)" // # then any text
"|" // - or -
"(?:\\h*)" // horiz-white
"$" // end of line
, boost::regex::perl |
boost::regex_constants::match_flags::match_not_dot_null
);
return re;
}
};
//------------------------------------------------------------------------------
bool Utilities::parseInfoLine (
Source::Info& info,
std::string const& line,
Journal journal)
{
bool success (false);
boost::smatch match;
if (boost::regex_match (line, match, Helpers::reInfo ()))
{
std::string const encodedKey (match [1]);
std::string const commentText (match [2]);
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))
{
// We got a public key.
RipplePublicKey publicKey (deprecatedPublicKey.toRipplePublicKey ());
success = true;
}
else
{
// Some other junk.
// log?
}
}
else if (boost::regex_match (line, match, Helpers::reComment ()))
{
// it's a comment
}
else
{
// Log a warning about a parsing error
}
#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;
}
//------------------------------------------------------------------------------
void Utilities::parseResultLine (
Source::Result& result,
std::string const& line,
Journal journal)
{
bool success = false;
if (! success)
{
Source::Info info;
success = parseInfoLine (info, line, journal);
if (success)
result.list.add (info);
}
}
}

View File

@@ -4,12 +4,15 @@
*/
//==============================================================================
#ifndef RIPPLE_CORE_VALIDATORSUTILITIES_H_INCLUDED
#define RIPPLE_CORE_VALIDATORSUTILITIES_H_INCLUDED
#ifndef RIPPLE_VALIDATORS_UTILITIES_H_INCLUDED
#define RIPPLE_VALIDATORS_UTILITIES_H_INCLUDED
namespace Validators
{
/** Common code for Validators classes.
*/
class ValidatorsUtilities
class Utilities
{
public:
typedef std::vector <std::string> Strings;
@@ -39,14 +42,20 @@ public:
Metadata lines will update the corresponding Result fields.
*/
static void parseResultLine (
Validators::Source::Result& result,
String line);
Source::Result& result,
std::string const& line,
Journal journal = Journal());
private:
struct Helpers;
/** Parse a string into a Source::Info.
@return `true` on success.
*/
static bool parseInfoLine (Validators::Source::Info& info, String line);
static bool parseInfoLine (
Source::Info& info, std::string const& line, Journal journal);
};
}
#endif

View File

@@ -1,733 +0,0 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
/*
Information to track:
- Percentage of validations that the validator has signed
- Number of validations the validator signed that never got accepted
- Target number for Chosen
- Pseudo-randomly choose a subset from Chosen
Goal:
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.
*/
//------------------------------------------------------------------------------
Validators::Source::Result::Result ()
: success (false)
, message ("uninitialized")
{
}
void Validators::Source::Result::swapWith (Result& other)
{
std::swap (success, other.success);
std::swap (message, other.message);
list.swapWith (other.list);
}
//------------------------------------------------------------------------------
class ValidatorsImp
: public Validators
, private ThreadWithCallQueue::EntryPoints
, private DeadlineTimer::Listener
, LeakChecked <ValidatorsImp>
{
public:
// Tunable constants
enum
{
// We will fetch a source at this interval
hoursBetweenFetches = 24
,secondsBetweenFetches = hoursBetweenFetches * 60 * 60
// Wake up every hour to check source times
,secondsPerUpdate = 60 * 60
// This tunes the preallocated arrays
,expectedNumberOfResults = 1000
};
//--------------------------------------------------------------------------
// Dummy CancelCallback that does nothing
//
struct NoOpCancelCallback : Source::CancelCallback
{
bool shouldCancel ()
{
return false;
}
};
//--------------------------------------------------------------------------
/** Receive event notifications on Validators operations.
*/
class Listener
{
public:
};
//--------------------------------------------------------------------------
class ChosenList : public SharedObject
{
public:
typedef SharedPtr <ChosenList> Ptr;
struct Info
{
Info ()
{
}
};
//typedef HashMap <KeyType, Info, KeyType::HashFunction> MapType;
typedef boost::unordered_map <KeyType, Info, KeyType::HashFunction> MapType;
ChosenList (std::size_t expectedSize = 0)
{
// Available only in recent boost versions?
//m_map.reserve (expectedSize);
}
std::size_t size () const noexcept
{
return m_map.size ();
}
void insert (KeyType const& key, Info const& info) noexcept
{
m_map [key] = info;
}
bool contains (KeyType const& key) const noexcept
{
return m_map.find (key) != m_map.cend ();
}
private:
MapType m_map;
};
//--------------------------------------------------------------------------
// Encapsulates the logic for creating the chosen validators.
// This is a separate class to facilitate the unit tests.
//
class Logic
{
public:
// Information associated with each Source
//
struct SourceDesc
{
enum
{
keysPreallocationSize = 1000
};
enum Status
{
statusNone,
statusFetched,
statusFailed
};
ScopedPointer <Source> source;
Status status;
Time whenToFetch;
int numberOfFailures;
// The result of the last fetch
Source::Result result;
//------------------------------------------------------------------
SourceDesc () noexcept
: status (statusNone)
, whenToFetch (Time::getCurrentTime ())
, numberOfFailures (0)
{
}
~SourceDesc ()
{
}
};
typedef DynamicList <SourceDesc> SourcesType;
//----------------------------------------------------------------------
// Information associated with each distinguishable validator
//
struct ValidatorInfo
{
ValidatorInfo ()
: refCount (0)
{
}
int refCount;
};
//typedef HashMap <KeyType, ValidatorInfo, KeyType::HashFunction> MapType;
typedef boost::unordered_map <KeyType, ValidatorInfo, KeyType::HashFunction> MapType;
//----------------------------------------------------------------------
Logic ()
: m_chosenListNeedsUpdate (false)
{
}
// Add a one-time static source.
// Fetch is called right away, this call blocks.
//
void addStaticSource (Source* source)
{
ScopedPointer <Source> object (source);
NoOpCancelCallback cancelCallback;
Source::Result result (object->fetch (cancelCallback));
if (result.success)
{
addSourceInfo (result.list);
}
else
{
// VFALCO NOTE Maybe log the error and message?
}
}
// Add a live source to the list of sources.
//
void addSource (Source* source)
{
SourceDesc& desc (*m_sources.emplace_back ());
desc.source = source;
}
// Called when we receive a validation from a peer.
//
void receiveValidation (Validators::ReceivedValidation const& rv)
{
MapType::iterator iter (m_map.find (rv.signerPublicKeyHash));
if (iter != m_map.end ())
{
// Exists
//ValidatorInfo& validatorInfo (iter->value ());
}
else
{
// New
//ValidatorInfo& validatorInfo (m_map.insert (rv.signerPublicKeyHash));
}
}
// Add each entry in the list to the map, incrementing the
// reference count if it already exists, and updating fields.
//
void addSourceInfo (Array <Source::Info> const& list)
{
for (std::size_t i = 0; i < list.size (); ++i)
{
Source::Info const& info (list.getReference (i));
std::pair <MapType::iterator, bool> result (
m_map.emplace (info.key, ValidatorInfo ()));
ValidatorInfo& validatorInfo (result.first->second);
++validatorInfo.refCount;
if (result.second)
{
// This is a new one
markDirtyChosenList ();
}
}
}
// Decrement the reference count of each item in the list
// in the map
//
void removeSourceInfo (Array <Source::Info> const& list)
{
for (std::size_t i = 0; i < list.size (); ++i)
{
Source::Info const& info (list.getReference (i));
MapType::iterator iter (m_map.find (info.key));
bassert (iter != m_map.end ());
ValidatorInfo& validatorInfo (iter->second);
if (--validatorInfo.refCount == 0)
{
// Last reference removed
m_map.erase (iter);
markDirtyChosenList ();
}
}
}
// Fetch one source
//
void fetchSource (SourceDesc& desc, Source::CancelCallback& callback)
{
Source::Result result (desc.source->fetch (callback));
if (! callback.shouldCancel ())
{
// Reset fetch timer for the source.
desc.whenToFetch = Time::getCurrentTime () +
RelativeTime (secondsBetweenFetches);
if (result.success)
{
// Add the new source info to the map
addSourceInfo (result.list);
// Swap lists
desc.result.swapWith (result);
// Remove the old source info from the map
removeSourceInfo (result.list);
// See if we need to rebuild
checkDirtyChosenList ();
// Reset failure status
desc.numberOfFailures = 0;
desc.status = SourceDesc::statusFetched;
}
else
{
++desc.numberOfFailures;
desc.status = SourceDesc::statusFailed;
}
}
}
// Check each source to see if it needs fetching.
//
void checkSources (Source::CancelCallback& callback)
{
Time const currentTime (Time::getCurrentTime ());
for (SourcesType::iterator iter = m_sources.begin ();
! callback.shouldCancel () && iter != m_sources.end (); ++iter)
{
SourceDesc& desc (*iter);
if (desc.whenToFetch <= currentTime)
fetchSource (desc, callback);
}
}
// Signal that the Chosen List needs to be rebuilt.
//
void markDirtyChosenList ()
{
m_chosenListNeedsUpdate = true;
}
// Check the dirty state of the Chosen List, and rebuild it
// if necessary.
//
void checkDirtyChosenList ()
{
if (m_chosenListNeedsUpdate)
{
buildChosenList ();
m_chosenListNeedsUpdate = false;
}
}
// Rebuilds the Chosen List
//
void buildChosenList ()
{
ChosenList::Ptr list (new ChosenList (m_map.size ()));
for (MapType::iterator iter = m_map.begin ();
iter != m_map.end (); ++iter)
{
ChosenList::Info info;
list->insert (iter->first, info);
}
// This is thread safe
m_chosenList = list;
}
// Get a reference to the chosen list.
// This is safe to call from any thread at any time.
//
ChosenList::Ptr getChosenList ()
{
return m_chosenList;
}
//----------------------------------------------------------------------
//
// Ripple interface
//
// These routines are modeled after UniqueNodeList
bool isTrustedPublicKeyHash (RipplePublicKeyHash const& key)
{
return m_chosenList->contains (key);
}
//
//
//----------------------------------------------------------------------
private:
SourcesType m_sources;
MapType m_map;
bool m_chosenListNeedsUpdate;
ChosenList::Ptr m_chosenList;
};
//--------------------------------------------------------------------------
public:
explicit ValidatorsImp (Listener* listener)
: m_listener (listener)
, m_thread ("Validators")
, m_timer (this)
{
m_thread.start (this);
}
~ValidatorsImp ()
{
}
void addStrings (std::vector <std::string> const& strings)
{
StringArray stringArray;
stringArray.ensureStorageAllocated (strings.size());
for (std::size_t i = 0; i < strings.size(); ++i)
stringArray.add (strings [i]);
addStrings (stringArray);
}
void addStrings (StringArray const& stringArray)
{
addStaticSource (
ValidatorSourceStrings::New (stringArray));
}
void addFile (File const& file)
{
addStaticSource (ValidatorSourceFile::New (file));
}
void addURL (UniformResourceLocator const& url)
{
addSource (ValidatorSourceURL::New (url));
}
void addSource (Source* source)
{
m_thread.call (&Logic::addSource, &m_logic, source);
}
void addStaticSource (Source* source)
{
m_thread.call (&Logic::addStaticSource, &m_logic, source);
}
void receiveValidation (ReceivedValidation const& rv)
{
m_thread.call (&Logic::receiveValidation, &m_logic, rv);
}
//--------------------------------------------------------------------------
void onDeadlineTimer (DeadlineTimer&)
{
// This will make us fall into the idle proc as needed
//
m_thread.interrupt ();
}
void threadInit ()
{
m_timer.setRecurringExpiration (secondsPerUpdate);
}
void threadExit ()
{
}
bool threadIdle ()
{
bool interrupted = false;
struct ThreadCancelCallback : Source::CancelCallback, Uncopyable
{
explicit ThreadCancelCallback (ThreadWithCallQueue& thread)
: m_thread (thread)
, m_interrupted (false)
{
}
bool shouldCancel ()
{
if (m_interrupted)
return true;
return m_interrupted = m_thread.interruptionPoint ();
}
private:
ThreadWithCallQueue& m_thread;
bool m_interrupted;
};
ThreadCancelCallback cancelCallback (m_thread);
m_logic.checkSources (cancelCallback);
return interrupted;
}
private:
Logic m_logic;
Listener* const m_listener;
ThreadWithCallQueue m_thread;
DeadlineTimer m_timer;
};
//------------------------------------------------------------------------------
Validators* Validators::New ()
{
return new ValidatorsImp (nullptr);
}
//------------------------------------------------------------------------------
class ValidatorsTests : public UnitTest
{
public:
enum
{
numberOfTestValidators = 1000
};
//--------------------------------------------------------------------------
struct Payload
{
Payload ()
{
}
};
template <class Config>
class PeerLogic : public TestOverlay::PeerLogicBase <Config>
{
public:
typedef TestOverlay::PeerLogicBase <Config> Base;
typedef typename Config::Payload Payload;
typedef typename Base::Connection Connection;
typedef typename Base::Peer Peer;
typedef typename Base::Message Message;
typedef typename Config::SizeType SizeType;
explicit PeerLogic (Peer& peer)
: TestOverlay::PeerLogicBase <Config> (peer)
{
}
~PeerLogic ()
{
}
void step ()
{
if (this->peer().id () == 1)
{
if (this->peer().network().steps() == 0)
{
this->peer().network().state().increment();
this->peer().send_all (Payload (1));
}
}
}
void receive (Connection const& c, Message const& m)
{
if (this->peer().id () != 1)
{
this->peer().network().state().increment();
this->peer().send_all_if (Message (m.id(),
m.payload().withHop ()),
typename Connection::IsNotPeer (c.peer()));
}
}
};
struct Params : TestOverlay::ConfigType <
Params,
TestOverlay::StateBase,
PeerLogic
>
{
typedef TestOverlay::PremadeInitPolicy <250, 3> InitPolicy;
};
typedef Params::Network Network;
//--------------------------------------------------------------------------
struct TestSource : Validators::Source
{
TestSource (String const& name, uint32 start, uint32 end)
: m_name (name)
, m_start (start)
, m_end (end)
{
}
Result fetch (CancelCallback& cancel)
{
Result result;
result.success = true;
result.message = String::empty;
result.list.ensureStorageAllocated (numberOfTestValidators);
for (uint32 i = m_start ; i < m_end; ++i)
{
Info info;
info.key = Validators::KeyType::createFromInteger (i);
result.list.add (info);
}
return result;
}
String m_name;
std::size_t m_start;
std::size_t m_end;
};
//--------------------------------------------------------------------------
void addSources (ValidatorsImp::Logic& logic)
{
#if 0
logic.addSource (new TestSource ("source 1", 0, 1000));
logic.addSource (new TestSource ("source 2", 200, 1500));
logic.addSource (new TestSource ("source 3", 500, 2000));
logic.addSource (new TestSource ("source 4", 750, 2200));
logic.addSource (new TestSource ("source 5", 1500, 3200));
#else
logic.addSource (new TestSource ("source 1", 0, 1));
#endif
}
void testLogic ()
{
beginTestCase ("logic");
ValidatorsImp::Logic logic;
addSources (logic);
ValidatorsImp::NoOpCancelCallback cancelCallback;
logic.checkSources (cancelCallback);
ValidatorsImp::ChosenList::Ptr list (logic.getChosenList ());
pass ();
}
void runTest ()
{
testLogic ();
}
ValidatorsTests () : UnitTest ("Validators", "ripple", runManual)
{
}
};
static ValidatorsTests validatorsTests;

View File

@@ -1,30 +0,0 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
bool ValidatorsUtilities::parseInfoLine (Validators::Source::Info& info, String line)
{
bool success (false);
return success;
}
void ValidatorsUtilities::parseResultLine (
Validators::Source::Result& result,
String line)
{
bool success = false;
if (! success)
{
Validators::Source::Info info;
success = parseInfoLine (info, line);
if (success)
result.list.add (info);
}
}

View File

@@ -9,24 +9,31 @@
#include "ripple_validators.h"
#include "beast/modules/beast_core/system/BeforeBoost.h" // must come first
//#include <boost/algorithm/string.hpp>
//#include <boost/foreach.hpp>
//#include <boost/unordered_map.hpp>
#include <boost/regex.hpp>
#include <boost/unordered_set.hpp>
#include "beast/modules/beast_sqdb/beast_sqdb.h"
#include "../testoverlay/ripple_testoverlay.h" // for unit test
namespace ripple
{
# include "impl/ValidatorsUtilities.h"
#include "impl/ValidatorsUtilities.cpp"
# include "impl/ValidatorSourceFile.h"
# include "impl/ValidatorSourceStrings.h"
# include "impl/ValidatorSourceURL.h"
#include "impl/ValidatorSourceFile.cpp"
#include "impl/ValidatorSourceStrings.cpp"
#include "impl/ValidatorSourceURL.cpp"
#include "impl/Validators.cpp"
# include "impl/CancelCallbacks.h"
# include "impl/ChosenList.h"
# include "impl/SourceFile.h"
# include "impl/SourceStrings.h"
# include "impl/SourceURL.h"
# include "impl/Store.h"
# include "impl/Utilities.h"
#include "impl/Logic.h"
#include "impl/Manager.cpp"
#include "impl/Source.cpp"
#include "impl/SourceFile.cpp"
#include "impl/SourceStrings.cpp"
#include "impl/SourceURL.cpp"
#include "impl/Tests.cpp"
#include "impl/Utilities.cpp"
}

View File

@@ -25,7 +25,9 @@ namespace ripple
using namespace beast;
#include "api/Validators.h"
# include "api/Types.h"
# include "api/Source.h"
#include "api/Manager.h"
}

View File

@@ -15,7 +15,8 @@ SETUP_LOG (Application)
//
// Specializations for LogPartition names
template <> char const* LogPartition::getPartitionName <Validators> () { return "Validators"; }
class ValidatorsLog;
template <> char const* LogPartition::getPartitionName <ValidatorsLog> () { return "Validators"; }
//
//------------------------------------------------------------------------------
@@ -165,7 +166,7 @@ public:
getConfig ().nodeDatabase,
getConfig ().ephemeralNodeDatabase,
*this))
, m_validators (Validators::New ())
, m_validators (Validators::Manager::New (LogJournal::get <ValidatorsLog> ()))
, mFeatures (IFeatures::New (2 * 7 * 24 * 60 * 60, 200)) // two weeks, 200/256
, mFeeVote (IFeeVote::New (10, 50 * SYSTEM_CURRENCY_PARTS, 12.5 * SYSTEM_CURRENCY_PARTS))
, mFeeTrack (ILoadFeeTrack::New ())
@@ -231,7 +232,7 @@ public:
{
std::vector <std::string> const& strings (getConfig().validators);
if (! strings.empty ())
m_validators->addStrings (strings);
m_validators->addStrings ("rippled.cfg", strings);
}
if (! getConfig().getValidatorsURL().empty())
@@ -333,7 +334,7 @@ public:
return mSLECache;
}
Validators& getValidators ()
Validators::Manager& getValidators ()
{
return *m_validators;
}
@@ -740,7 +741,7 @@ private:
ScopedPointer <SSLContext> m_wsSSLContext;
ScopedPointer <TxQueue> m_txQueue;
ScopedPointer <NodeStore> m_nodeStore;
ScopedPointer <Validators> m_validators;
ScopedPointer <Validators::Manager> m_validators;
ScopedPointer <IFeatures> mFeatures;
ScopedPointer <IFeeVote> mFeeVote;
ScopedPointer <ILoadFeeTrack> mFeeTrack;

View File

@@ -7,6 +7,8 @@
#ifndef RIPPLE_IAPPLICATION_H
#define RIPPLE_IAPPLICATION_H
namespace Validators { class Manager; }
// VFALCO TODO Fix forward declares required for header dependency loops
class IFeatures;
class IFeeVote;
@@ -14,7 +16,6 @@ class IHashRouter;
class ILoadFeeTrack;
class Peers;
class UniqueNodeList;
class Validators;
class NodeStore;
class JobQueue;
@@ -79,7 +80,7 @@ public:
virtual NodeCache& getTempNodeCache () = 0;
virtual SLECache& getSLECache () = 0;
virtual Validators& getValidators () = 0;
virtual Validators::Manager& getValidators () = 0;
virtual IFeatures& getFeatureTable () = 0;
virtual IFeeVote& getFeeVote () = 0;
virtual IHashRouter& getHashRouter () = 0;