Validators framework and unit test

This commit is contained in:
Vinnie Falco
2013-09-02 18:23:45 -07:00
parent 2e1167fbd9
commit 91e0cc84ef
28 changed files with 948 additions and 727 deletions

View File

@@ -778,25 +778,25 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\modules\ripple_core\ripple_core.cpp" />
<ClCompile Include="..\..\modules\ripple_core\validator\ripple_StringsValidatorSource.cpp">
<ClCompile Include="..\..\modules\ripple_core\validator\ValidatorSourceStrings.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="..\..\modules\ripple_core\validator\ripple_TrustedUriValidatorSource.cpp">
<ClCompile Include="..\..\modules\ripple_core\validator\ValidatorSourceTrustedUri.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="..\..\modules\ripple_core\validator\ripple_Validator.cpp">
<ClCompile Include="..\..\modules\ripple_core\validator\Validator.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="..\..\modules\ripple_core\validator\ripple_Validators.cpp">
<ClCompile Include="..\..\modules\ripple_core\validator\Validators.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
@@ -1398,13 +1398,13 @@
<ClInclude Include="..\..\modules\ripple_app\misc\ripple_IFeeVote.h" />
<ClInclude Include="..\..\modules\ripple_app\misc\ripple_IHashRouter.h" />
<ClInclude Include="..\..\modules\ripple_app\misc\ProofOfWorkFactory.h" />
<ClInclude Include="..\..\modules\ripple_app\misc\ripple_IValidations.h" />
<ClInclude Include="..\..\modules\ripple_app\misc\ripple_NicknameState.h" />
<ClInclude Include="..\..\modules\ripple_app\misc\ripple_Offer.h" />
<ClInclude Include="..\..\modules\ripple_app\misc\ripple_OrderBook.h" />
<ClInclude Include="..\..\modules\ripple_app\misc\ProofOfWork.h" />
<ClInclude Include="..\..\modules\ripple_app\misc\ripple_SerializedLedger.h" />
<ClInclude Include="..\..\modules\ripple_app\misc\ripple_SerializedTransaction.h" />
<ClInclude Include="..\..\modules\ripple_app\misc\ripple_Validations.h" />
<ClInclude Include="..\..\modules\ripple_app\node\ripple_SqliteBackendFactory.h" />
<ClInclude Include="..\..\modules\ripple_app\paths\ripple_Pathfinder.h" />
<ClInclude Include="..\..\modules\ripple_app\paths\ripple_PathRequest.h" />
@@ -1501,12 +1501,11 @@
<ClInclude Include="..\..\modules\ripple_core\node\NodeStore.h" />
<ClInclude Include="..\..\modules\ripple_core\node\NullBackendFactory.h" />
<ClInclude Include="..\..\modules\ripple_core\ripple_core.h" />
<ClInclude Include="..\..\modules\ripple_core\validator\ripple_StringsValidatorSource.h" />
<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_ValidatorImp.h" />
<ClInclude Include="..\..\modules\ripple_core\validator\ripple_Validators.h" />
<ClInclude Include="..\..\modules\ripple_core\validator\ValidatorSourceStrings.h" />
<ClInclude Include="..\..\modules\ripple_core\validator\ValidatorSourceTrustedUri.h" />
<ClInclude Include="..\..\modules\ripple_core\validator\Validator.h" />
<ClInclude Include="..\..\modules\ripple_core\validator\ValidatorsImp.h" />
<ClInclude Include="..\..\modules\ripple_core\validator\Validators.h" />
<ClInclude Include="..\..\modules\ripple_data\crypto\ripple_Base58.h" />
<ClInclude Include="..\..\modules\ripple_data\crypto\ripple_Base58Data.h" />
<ClInclude Include="..\..\modules\ripple_data\crypto\ripple_CBigNum.h" />

View File

@@ -159,18 +159,6 @@
<ClCompile Include="..\..\src\cpp\protobuf_core.cpp">
<Filter>[0] Subtrees\protobuf</Filter>
</ClCompile>
<ClCompile Include="..\..\modules\ripple_app\ripple_app_pt1.cpp">
<Filter>[1] Ripple\ripple_app</Filter>
</ClCompile>
<ClCompile Include="..\..\modules\ripple_app\ripple_app_pt2.cpp">
<Filter>[1] Ripple\ripple_app</Filter>
</ClCompile>
<ClCompile Include="..\..\modules\ripple_app\ripple_app_pt3.cpp">
<Filter>[1] Ripple\ripple_app</Filter>
</ClCompile>
<ClCompile Include="..\..\modules\ripple_app\ripple_app_pt4.cpp">
<Filter>[1] Ripple\ripple_app</Filter>
</ClCompile>
<ClCompile Include="..\..\modules\ripple_basics\containers\ripple_RangeSet.cpp">
<Filter>[1] Ripple\ripple_basics\containers</Filter>
</ClCompile>
@@ -477,6 +465,18 @@
<ClCompile Include="..\..\Subtrees\leveldb\port\port_win.cc">
<Filter>[0] Subtrees\leveldb\port</Filter>
</ClCompile>
<ClCompile Include="..\..\modules\ripple_app\ripple_app_pt1.cpp">
<Filter>[1] Ripple\ripple_app</Filter>
</ClCompile>
<ClCompile Include="..\..\modules\ripple_app\ripple_app_pt2.cpp">
<Filter>[1] Ripple\ripple_app</Filter>
</ClCompile>
<ClCompile Include="..\..\modules\ripple_app\ripple_app_pt3.cpp">
<Filter>[1] Ripple\ripple_app</Filter>
</ClCompile>
<ClCompile Include="..\..\modules\ripple_app\ripple_app_pt4.cpp">
<Filter>[1] Ripple\ripple_app</Filter>
</ClCompile>
<ClCompile Include="..\..\modules\ripple_app\ripple_app_pt5.cpp">
<Filter>[1] Ripple\ripple_app</Filter>
</ClCompile>
@@ -528,12 +528,6 @@
<ClCompile Include="..\..\modules\ripple_app\data\ripple_SqliteDatabase.cpp">
<Filter>[1] Ripple\ripple_app\data</Filter>
</ClCompile>
<ClCompile Include="..\..\modules\ripple_core\validator\ripple_Validator.cpp">
<Filter>[1] Ripple\ripple_core\validator</Filter>
</ClCompile>
<ClCompile Include="..\..\modules\ripple_core\validator\ripple_Validators.cpp">
<Filter>[1] Ripple\ripple_core\validator</Filter>
</ClCompile>
<ClCompile Include="..\..\modules\ripple_app\ledger\Ledger.cpp">
<Filter>[1] Ripple\ripple_app\ledger</Filter>
</ClCompile>
@@ -570,12 +564,6 @@
<ClCompile Include="..\..\modules\ripple_app\ledger\SerializedValidation.cpp">
<Filter>[1] Ripple\ripple_app\ledger</Filter>
</ClCompile>
<ClCompile Include="..\..\modules\ripple_core\validator\ripple_TrustedUriValidatorSource.cpp">
<Filter>[1] Ripple\ripple_core\validator</Filter>
</ClCompile>
<ClCompile Include="..\..\modules\ripple_core\validator\ripple_StringsValidatorSource.cpp">
<Filter>[1] Ripple\ripple_core\validator</Filter>
</ClCompile>
<ClCompile Include="..\..\Subtrees\beast\modules\beast_crypto\beast_crypto.cpp">
<Filter>[0] Subtrees\beast</Filter>
</ClCompile>
@@ -864,6 +852,18 @@
<ClCompile Include="..\..\modules\ripple_core\node\NullBackendFactory.cpp">
<Filter>[1] Ripple\ripple_core\node</Filter>
</ClCompile>
<ClCompile Include="..\..\modules\ripple_core\validator\ValidatorSourceStrings.cpp">
<Filter>[1] Ripple\ripple_core\validator</Filter>
</ClCompile>
<ClCompile Include="..\..\modules\ripple_core\validator\ValidatorSourceTrustedUri.cpp">
<Filter>[1] Ripple\ripple_core\validator</Filter>
</ClCompile>
<ClCompile Include="..\..\modules\ripple_core\validator\Validator.cpp">
<Filter>[1] Ripple\ripple_core\validator</Filter>
</ClCompile>
<ClCompile Include="..\..\modules\ripple_core\validator\Validators.cpp">
<Filter>[1] Ripple\ripple_core\validator</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\modules\ripple_app\ripple_app.h">
@@ -1286,12 +1286,6 @@
<ClInclude Include="..\..\modules\ripple_app\data\ripple_SqliteDatabase.h">
<Filter>[1] Ripple\ripple_app\data</Filter>
</ClInclude>
<ClInclude Include="..\..\modules\ripple_core\validator\ripple_Validator.h">
<Filter>[1] Ripple\ripple_core\validator</Filter>
</ClInclude>
<ClInclude Include="..\..\modules\ripple_core\validator\ripple_Validators.h">
<Filter>[1] Ripple\ripple_core\validator</Filter>
</ClInclude>
<ClInclude Include="..\..\modules\ripple_app\ledger\Ledger.h">
<Filter>[1] Ripple\ripple_app\ledger</Filter>
</ClInclude>
@@ -1328,15 +1322,6 @@
<ClInclude Include="..\..\modules\ripple_app\ledger\SerializedValidation.h">
<Filter>[1] Ripple\ripple_app\ledger</Filter>
</ClInclude>
<ClInclude Include="..\..\modules\ripple_core\validator\ripple_ValidatorList.h">
<Filter>[1] Ripple\ripple_core\validator</Filter>
</ClInclude>
<ClInclude Include="..\..\modules\ripple_core\validator\ripple_TrustedUriValidatorSource.h">
<Filter>[1] Ripple\ripple_core\validator</Filter>
</ClInclude>
<ClInclude Include="..\..\modules\ripple_core\validator\ripple_StringsValidatorSource.h">
<Filter>[1] Ripple\ripple_core\validator</Filter>
</ClInclude>
<ClInclude Include="..\..\modules\ripple_core\functional\ripple_ConfigSections.h">
<Filter>[1] Ripple\ripple_core\functional</Filter>
</ClInclude>
@@ -1373,9 +1358,6 @@
<ClInclude Include="..\..\modules\ripple_app\misc\ripple_IHashRouter.h">
<Filter>[1] Ripple\ripple_app\misc</Filter>
</ClInclude>
<ClInclude Include="..\..\modules\ripple_app\misc\ripple_IValidations.h">
<Filter>[1] Ripple\ripple_app\misc</Filter>
</ClInclude>
<ClInclude Include="..\..\modules\ripple_app\misc\ripple_NicknameState.h">
<Filter>[1] Ripple\ripple_app\misc</Filter>
</ClInclude>
@@ -1499,9 +1481,6 @@
<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>
<ClInclude Include="..\..\modules\ripple_app\main\ripple_FatalErrorReporter.h">
<Filter>[1] Ripple\ripple_app\main</Filter>
</ClInclude>
@@ -1688,6 +1667,24 @@
<ClInclude Include="..\..\modules\ripple_core\node\NullBackendFactory.h">
<Filter>[1] Ripple\ripple_core\node</Filter>
</ClInclude>
<ClInclude Include="..\..\modules\ripple_app\misc\ripple_Validations.h">
<Filter>[1] Ripple\ripple_app\misc</Filter>
</ClInclude>
<ClInclude Include="..\..\modules\ripple_core\validator\ValidatorSourceStrings.h">
<Filter>[1] Ripple\ripple_core\validator</Filter>
</ClInclude>
<ClInclude Include="..\..\modules\ripple_core\validator\ValidatorSourceTrustedUri.h">
<Filter>[1] Ripple\ripple_core\validator</Filter>
</ClInclude>
<ClInclude Include="..\..\modules\ripple_core\validator\Validator.h">
<Filter>[1] Ripple\ripple_core\validator</Filter>
</ClInclude>
<ClInclude Include="..\..\modules\ripple_core\validator\Validators.h">
<Filter>[1] Ripple\ripple_core\validator</Filter>
</ClInclude>
<ClInclude Include="..\..\modules\ripple_core\validator\ValidatorsImp.h">
<Filter>[1] Ripple\ripple_core\validator</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<CustomBuild Include="..\..\modules\ripple_data\protocol\ripple.proto">

View File

@@ -33,7 +33,7 @@ SerializedValidation::SerializedValidation (
assert (mNodeID.isNonZero ());
if (!isFull)
setFlag (sFullFlag);
setFlag (kFullFlag);
}
void SerializedValidation::sign (const RippleAddress& raPriv)
@@ -98,7 +98,7 @@ RippleAddress SerializedValidation::getSignerPublic () const
bool SerializedValidation::isFull () const
{
return (getFlags () & sFullFlag) != 0;
return (getFlags () & kFullFlag) != 0;
}
Blob SerializedValidation::getSignature () const

View File

@@ -17,7 +17,10 @@ public:
typedef boost::shared_ptr<SerializedValidation> pointer;
typedef const boost::shared_ptr<SerializedValidation>& ref;
static const uint32 sFullFlag = 0x1;
enum
{
kFullFlag = 0x1
};
// These throw if the object is not valid
SerializedValidation (SerializerIterator & sit, bool checkSignature = true);

View File

@@ -15,7 +15,6 @@ SETUP_LOG (Application)
class ApplicationImp
: public Application
, public SharedSingleton <ApplicationImp>
, public Validators::Listener
, public NodeStore::Scheduler
, LeakChecked <ApplicationImp>
{
@@ -168,12 +167,12 @@ public:
getConfig ().nodeDatabase,
getConfig ().ephemeralNodeDatabase,
*this))
, m_validators (Validators::New (this))
, m_validators (Validators::New ())
, 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 ())
, mHashRouter (IHashRouter::New (IHashRouter::getDefaultHoldTime ()))
, mValidations (IValidations::New ())
, mValidations (Validations::New ())
, mUNL (UniqueNodeList::New ())
, mProofOfWorkFactory (ProofOfWorkFactory::New ())
, m_loadManager (LoadManager::New ())
@@ -313,7 +312,7 @@ public:
return *mHashRouter;
}
IValidations& getValidations ()
Validations& getValidations ()
{
return *mValidations;
}
@@ -697,7 +696,7 @@ private:
ScopedPointer <IFeeVote> mFeeVote;
ScopedPointer <ILoadFeeTrack> mFeeTrack;
ScopedPointer <IHashRouter> mHashRouter;
ScopedPointer <IValidations> mValidations;
ScopedPointer <Validations> mValidations;
ScopedPointer <UniqueNodeList> mUNL;
ScopedPointer <ProofOfWorkFactory> mProofOfWorkFactory;
ScopedPointer <Peers> m_peers;
@@ -819,43 +818,33 @@ void ApplicationImp::doSweep(Job& j)
logTimedCall <Application> ("TransactionMaster::sweep", __FILE__, __LINE__, boost::bind (
&TransactionMaster::sweep, &mMasterTransaction));
//mMasterTransaction.sweep ();
logTimedCall <Application> ("NodeStore::sweep", __FILE__, __LINE__, boost::bind (
&NodeStore::sweep, m_nodeStore.get ()));
//m_nodeStore->sweep ();
logTimedCall <Application> ("LedgerMaster::sweep", __FILE__, __LINE__, boost::bind (
&LedgerMaster::sweep, &m_ledgerMaster));
//m_ledgerMaster.sweep ();
logTimedCall <Application> ("TempNodeCache::sweep", __FILE__, __LINE__, boost::bind (
&NodeCache::sweep, &mTempNodeCache));
//mTempNodeCache.sweep ();
logTimedCall <Application> ("Validations::sweep", __FILE__, __LINE__, boost::bind (
&IValidations::sweep, mValidations.get ()));
//mValidations->sweep ();
&Validations::sweep, mValidations.get ()));
logTimedCall <Application> ("InboundLedgers::sweep", __FILE__, __LINE__, boost::bind (
&InboundLedgers::sweep, &getInboundLedgers ()));
//getInboundLedgers ().sweep ();
logTimedCall <Application> ("SLECache::sweep", __FILE__, __LINE__, boost::bind (
&SLECache::sweep, &mSLECache));
//mSLECache.sweep ();
logTimedCall <Application> ("AcceptedLedger::sweep", __FILE__, __LINE__,
&AcceptedLedger::sweep);
//AcceptedLedger::sweep (); // VFALCO NOTE AcceptedLedger is/has a singleton?
logTimedCall <Application> ("SHAMap::sweep", __FILE__, __LINE__,
&SHAMap::sweep);
//SHAMap::sweep (); // VFALCO NOTE SHAMap is/has a singleton?
logTimedCall <Application> ("NetworkOPs::sweepFetchPack", __FILE__, __LINE__, boost::bind (
&NetworkOPs::sweepFetchPack, m_networkOPs.get ()));
//m_networkOPs->sweepFetchPack ();
// VFALCO NOTE does the call to sweep() happen on another thread?
mSweepTimer.expires_from_now (boost::posix_time::seconds (getConfig ().getSize (siSweepInterval)));

View File

@@ -14,7 +14,6 @@ class IHashRouter;
class ILoadFeeTrack;
class Peers;
class UniqueNodeList;
class IValidations;
class Validators;
class NodeStore;
@@ -86,8 +85,7 @@ public:
virtual Peers& getPeers () = 0;
virtual ProofOfWorkFactory& getProofOfWorkFactory () = 0;
virtual UniqueNodeList& getUNL () = 0;
virtual IValidations& getValidations () = 0;
virtual Validations& getValidations () = 0;
virtual NodeStore& getNodeStore () = 0;
virtual JobQueue& getJobQueue () = 0;
virtual InboundLedgers& getInboundLedgers () = 0;

View File

@@ -4,14 +4,14 @@
*/
//==============================================================================
class Validations;
class ValidationsImp;
SETUP_LOG (Validations)
typedef std::map<uint160, SerializedValidation::pointer>::value_type u160_val_pair;
typedef boost::shared_ptr<ValidationSet> VSpointer;
class Validations : public IValidations
class ValidationsImp : public Validations
{
private:
typedef RippleMutex LockType;
@@ -45,7 +45,7 @@ private:
}
public:
Validations ()
ValidationsImp ()
: mLock (this, "Validations", __FILE__, __LINE__)
, mValidations ("Validations", 128, 600), mWriting (false)
{
@@ -394,7 +394,7 @@ private:
mWriting = true;
getApp().getJobQueue ().addJob (jtWRITE, "Validations::doWrite",
BIND_TYPE (&Validations::doWrite, this, P_1));
BIND_TYPE (&ValidationsImp::doWrite, this, P_1));
}
void doWrite (Job&)
@@ -443,9 +443,9 @@ private:
}
};
IValidations* IValidations::New ()
Validations* Validations::New ()
{
return new Validations;
return new ValidationsImp;
}
// vim:ts=4

View File

@@ -4,19 +4,19 @@
*/
//==============================================================================
#ifndef RIPPLE_IVALIDATIONS_H
#define RIPPLE_IVALIDATIONS_H
#ifndef RIPPLE_VALIDATIONS_H_INCLUDED
#define RIPPLE_VALIDATIONS_H_INCLUDED
// VFALCO TODO rename and move these typedefs into the IValidations interface
// VFALCO TODO rename and move these typedefs into the Validations interface
typedef boost::unordered_map<uint160, SerializedValidation::pointer> ValidationSet;
typedef std::pair<int, uint160> currentValidationCount; // nodes validating and highest node ID validating
class IValidations : LeakChecked <IValidations>
class Validations : LeakChecked <Validations>
{
public:
static IValidations* New ();
static Validations* New ();
virtual ~IValidations () { }
virtual ~Validations () { }
virtual bool addValidation (SerializedValidation::ref, const std::string& source) = 0;

View File

@@ -1468,6 +1468,19 @@ static void checkValidation (Job&, SerializedValidation::pointer val, bool isTru
std::set<uint64> peers;
//----------------------------------------------------------------------
//
{
SerializedValidation const& sv (*val);
Validators::ReceivedValidation rv;
rv.ledgerHash = sv.getLedgerHash ();
uint160 const publicKeyHash (sv.getSignerPublic ().getNodeID ());
rv.signerPublicKeyHash = RipplePublicKeyHash (publicKeyHash.begin ());
getApp ().getValidators ().receiveValidation (rv);
}
//
//----------------------------------------------------------------------
if (getApp().getOPs ().recvValidation (val, source) &&
getApp().getHashRouter ().swapSet (signingHash, peers, SF_RELAYED))
{

View File

@@ -78,7 +78,7 @@ namespace ripple
#include "peers/ripple_Peers.h"
#include "peers/ripple_ClusterNodeStatus.h"
#include "peers/ripple_UniqueNodeList.h"
#include "misc/ripple_IValidations.h"
#include "misc/ripple_Validations.h"
#include "peers/ripple_PeerSet.h"
#include "ledger/ripple_InboundLedger.h"
#include "ledger/ripple_InboundLedgers.h"

View File

@@ -27,4 +27,12 @@ typedef UntrackedMutexType <boost::recursive_mutex> RippleRecursiveMutex;
typedef boost::recursive_mutex DeprecatedRecursiveMutex;
typedef DeprecatedRecursiveMutex::scoped_lock DeprecatedScopedLock;
//------------------------------------------------------------------------------
/** A container used to hold a public key in binary format. */
typedef UnsignedInteger <33> RipplePublicKey;
/** A container holding the hash of a public key in binary format. */
typedef UnsignedInteger <20> RipplePublicKeyHash;
#endif

View File

@@ -46,10 +46,13 @@ namespace ripple
#include "node/NodeStore.cpp"
#include "node/NodeObject.cpp"
#include "validator/ripple_Validator.cpp"
#include "validator/ripple_ValidatorImp.h" // private
#include "validator/ripple_Validators.cpp"
#include "validator/ripple_StringsValidatorSource.cpp"
#include "validator/ripple_TrustedUriValidatorSource.cpp"
# include "validator/Validator.h"
#include "validator/Validator.cpp"
# include "validator/ValidatorSourceStrings.h"
# include "validator/ValidatorSourceTrustedUri.h"
# include "validator/ValidatorsImp.h" // private
#include "validator/ValidatorSourceStrings.cpp"
#include "validator/ValidatorSourceTrustedUri.cpp"
#include "validator/Validators.cpp"
}

View File

@@ -28,11 +28,7 @@ namespace ripple
#include "node/NodeObject.h"
#include "node/NodeStore.h"
#include "validator/ripple_Validator.h"
#include "validator/ripple_ValidatorList.h"
#include "validator/ripple_Validators.h"
#include "validator/ripple_StringsValidatorSource.h"
#include "validator/ripple_TrustedUriValidatorSource.h"
#include "validator/Validators.h"
}

View File

@@ -4,7 +4,7 @@
*/
//==============================================================================
Validator::Validator (PublicKey const& publicKey)
Validator::Validator (RipplePublicKey const& publicKey)
: m_publicKey (publicKey)
{
}

View File

@@ -4,8 +4,8 @@
*/
//==============================================================================
#ifndef RIPPLE_VALIDATOR_H_INCLUDED
#define RIPPLE_VALIDATOR_H_INCLUDED
#ifndef RIPPLE_CORE_VALIDATOR_VALIDATOR_H_INCLUDED
#define RIPPLE_CORE_VALIDATOR_VALIDATOR_H_INCLUDED
//------------------------------------------------------------------------------
@@ -18,6 +18,8 @@
class Validator : public SharedObject
{
public:
typedef SharedObjectPtr <Validator> Ptr;
/** Fixed information on a validator.
This describes a validator.
@@ -41,12 +43,7 @@ public:
}
};
// VFALCO TODO magic number argh!!!
// This type should be located elsewhere.
//
typedef UnsignedInteger <33> PublicKey;
PublicKey publicKey;
RipplePublicKey publicKey;
//String friendlyName;
//String organizationType;
//String jurisdicton;
@@ -74,10 +71,6 @@ public:
}
};
typedef SharedObjectPtr <Validator> Ptr;
typedef Info::PublicKey PublicKey;
//--------------------------------------------------------------------------
// Comparison function for Validator objects
@@ -135,12 +128,12 @@ public:
//--------------------------------------------------------------------------
explicit Validator (PublicKey const& publicKey);
explicit Validator (RipplePublicKey const& publicKey);
PublicKey const& getPublicKey () const { return m_publicKey; }
RipplePublicKey const& getPublicKey () const { return m_publicKey; }
private:
PublicKey const m_publicKey;
RipplePublicKey const m_publicKey;
};

View File

@@ -0,0 +1,34 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
class ValidatorSourceStringsImp : public ValidatorSourceStrings
{
public:
ValidatorSourceStringsImp (StringArray const& strings)
{
}
~ValidatorSourceStringsImp ()
{
}
Array <Info> fetch (CancelCallback&)
{
return Array <Info> ();
}
private:
};
//------------------------------------------------------------------------------
ValidatorSourceStrings* ValidatorSourceStrings::New (StringArray const& strings)
{
ScopedPointer <ValidatorSourceStrings> object (
new ValidatorSourceStringsImp (strings));
return object.release ();
}

View File

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

View File

@@ -0,0 +1,36 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
class ValidatorSourceTrustedUriImp : public ValidatorSourceTrustedUri
{
public:
explicit ValidatorSourceTrustedUriImp (String const& uri)
: m_uri (uri)
{
}
~ValidatorSourceTrustedUriImp ()
{
}
Array <Info> fetch (CancelCallback&)
{
return Array <Info> ();
}
private:
String const m_uri;
};
//------------------------------------------------------------------------------
ValidatorSourceTrustedUri* ValidatorSourceTrustedUri::New (String const& uri)
{
ScopedPointer <ValidatorSourceTrustedUri> object (
new ValidatorSourceTrustedUriImp (uri));
return object.release ();
}

View File

@@ -4,15 +4,15 @@
*/
//==============================================================================
#ifndef RIPPLE_TRUSTEDURIVALIDATORSOURCE_H_INCLUDED
#define RIPPLE_TRUSTEDURIVALIDATORSOURCE_H_INCLUDED
#ifndef RIPPLE_CORE_VALIDATOR_VALIDATORSOURCETRUSTEDURI_H_INCLUDED
#define RIPPLE_CORE_VALIDATOR_VALIDATORSOURCETRUSTEDURI_H_INCLUDED
/** Provides validators from a trusted URI (e.g. HTTPS)
*/
class TrustedUriValidatorSource : public Validators::Source
class ValidatorSourceTrustedUri : public Validators::Source
{
public:
static TrustedUriValidatorSource* New (String url);
static ValidatorSourceTrustedUri* New (String const& uri);
};
#endif

View File

@@ -0,0 +1,209 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
/*
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:
I've cut 2 of the 6 active client-facing servers to hyper. Since then, we've
had 5 spinouts on 3 servers, none of them on the 2 I've cut over. But they
are also the most recently restarted servers, so it's not a 100% fair test.
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.
Nouns
Validator
- Signs ledgers and participate in consensus
- Fields
* Public key
* Friendly name
* Jurisdiction
* Org type: profit, nonprofit, "profit/gateway"
- Metadata
* Visible on the network?
* On the consensus ledger?
* Percentage of recent participation in consensus
* Frequency of stalling the consensus process
ValidatorSource
- Abstract
- Provides a list of Validator
ValidatorList
- Essentially an array of Validator
ValidatorSourceTrustedUri
- ValidatorSource which uses HTTPS and a predefined URI
- Domain owner is responsible for removing bad validators
ValidatorSourceTrustedUri::List
- Essentially an array of ValidatorSourceTrustedUri
- Can be read from a file
LocalFileValidatorSource
- ValidatorSource which reads information from a local file.
TrustedUriList // A copy of this ships with the app
* has a KnownValidators
KnownValidators
* A series of KnownValidator that comes from a TrustedUri
* Persistent storage has a timestamp
RankedValidators
* Created as the union of all KnownValidators with "weight" being the
number of appearances.
ChosenValidators
* Result of the algorithm that chooses a random subset of RankedKnownValidators
* "local health" percentage is the percent of validations from this list that
you've seen recently. And have they been behaving.
*/
//------------------------------------------------------------------------------
Validators* Validators::New ()
{
return new ValidatorsImp (nullptr);
}
//------------------------------------------------------------------------------
class ValidatorsTests : public UnitTest
{
public:
enum
{
numberOfTestValidators = 1000
};
struct TestSource : Validators::Source
{
TestSource (String const& name, uint32 start, uint32 end)
: m_name (name)
, m_start (start)
, m_end (end)
{
}
Array <Info> fetch (CancelCallback& cancel)
{
Array <Info> list;
list.ensureStorageAllocated (numberOfTestValidators);
for (uint32 i = m_start ; i < m_end; ++i)
{
Info info;
info.key = Validators::KeyType::createFromInteger (i);
list.add (info);
}
return list;
}
String m_name;
std::size_t m_start;
std::size_t m_end;
};
//--------------------------------------------------------------------------
void addSources (ValidatorsImp::Logic& logic)
{
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));
}
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

@@ -0,0 +1,107 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
#ifndef RIPPLE_CORE_VALIDATOR_VALIDATORS_H_INCLUDED
#define RIPPLE_CORE_VALIDATOR_VALIDATORS_H_INCLUDED
/** Maintains the list of chosen validators.
The algorithm for acquiring, building, and calculating metadata on
the list of chosen validators is critical to the health of the network.
All operations are performed asynchronously on an internal thread.
*/
class Validators : 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.
*/
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.
*/
virtual Array <Info> fetch (CancelCallback& callback) = 0;
};
//--------------------------------------------------------------------------
/** Create a new Validators object.
*/
static Validators* New ();
/** Destroy the object.
Any pending source fetch operations are aborted.
There may be some listener calls made before the
destructor returns.
*/
virtual ~Validators () { }
/** Add a live source of validators.
The caller loses ownership of the object.
Thread safety:
Can be called from any thread.
*/
virtual void addSource (Source* source) = 0;
/** Add a static source of validators.
The Source is called to fetch once and the results are kept
permanently. The fetch is performed asynchronously, this call
returns immediately. If the fetch fails, it is not reattempted.
The caller loses ownership of the object.
Thread safety:
Can be called from any thread.
*/
virtual void addStaticSource (Source* source) = 0;
//--------------------------------------------------------------------------
// Trusted Validators
//virtual bool isPublicKeyTrusted (Validator::PublicKey const&) = 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,438 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
#ifndef RIPPLE_CORE_VALIDATOR_VALIDATORSIMP_H_INCLUDED
#define RIPPLE_CORE_VALIDATOR_VALIDATORSIMP_H_INCLUDED
// private implementation
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 SharedObjectPtr <ChosenList> Ptr;
struct Info
{
Info ()
{
}
};
typedef HashMap <KeyType, Info, KeyType::HashFunction> MapType;
ChosenList ()
{
}
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 SourceInfo
{
enum
{
keysPreallocationSize = 1000
};
enum Status
{
statusNone,
statusFetched,
statusFailed
};
ScopedPointer <Source> source;
Status status;
Time whenToFetch;
int numberOfFailures;
// The result of hte last fetch
Array <Source::Info> list;
//------------------------------------------------------------------
SourceInfo () noexcept
: status (statusNone)
, whenToFetch (Time::getCurrentTime ())
, numberOfFailures (0)
{
list.ensureStorageAllocated (keysPreallocationSize);
}
~SourceInfo ()
{
}
};
typedef DynamicList <SourceInfo> SourcesType;
//----------------------------------------------------------------------
// Information associated with each distinguishable validator
//
struct ValidatorInfo
{
ValidatorInfo ()
: refCount (0)
{
}
KeyType key;
int refCount;
};
typedef HashMap <KeyType, ValidatorInfo, KeyType::HashFunction> MapType;
//----------------------------------------------------------------------
Logic ()
: m_chosenListNeedsUpdate (false)
{
}
// Add a live source to the list of sources.
//
void addSource (Source* source)
{
SourceInfo& info (*m_sources.emplace_back ());
info.source = source;
}
// Add a one-time static source.
// Fetch is called right away, this call blocks.
//
void addStaticSource (Source* source)
{
ScopedPointer <Source> object (source);
NoOpCancelCallback cancelCallback;
Array <Source::Info> list (object->fetch (cancelCallback));
addSourceInfo (list);
}
// 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));
MapType::Result result (m_map.insert (info.key));
ValidatorInfo& validatorInfo (result.iter->value ());
++validatorInfo.refCount;
if (result.inserted)
{
// 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->value ());
if (--validatorInfo.refCount == 0)
{
// Last reference removed
m_map.erase (info.key);
markDirtyChosenList ();
}
}
}
// Fetch one source
//
void fetchSource (SourceInfo& info, Source::CancelCallback& callback)
{
Array <Source::Info> list (info.source->fetch (callback));
if (! callback.shouldCancel ())
{
// Reset fetch timer for the source.
info.whenToFetch = Time::getCurrentTime () +
RelativeTime (secondsBetweenFetches);
// Add the new source info to the map
addSourceInfo (list);
// Swap lists
info.list.swapWith (list);
// Remove the old source info from the map
removeSourceInfo (list);
// See if we need to rebuild
checkDirtyChosenList ();
}
}
// 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)
{
SourceInfo& info (*iter);
if (info.whenToFetch <= currentTime)
fetchSource (info, 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);
for (MapType::iterator iter = m_map.begin ();
iter != m_map.end (); ++iter)
{
//ValidatorInfo const& validatorInfo (iter->value ());
ChosenList::Info info;
list->insert (iter->key (), 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 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;
};
#endif

View File

@@ -1,29 +0,0 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
class StringsValidatorSourceImp : public StringsValidatorSource
{
public:
StringsValidatorSourceImp (StringArray const& strings)
{
}
~StringsValidatorSourceImp ()
{
}
Array <Validator::Info> fetch ()
{
return Array <Validator::Info> ();
}
private:
};
StringsValidatorSource* StringsValidatorSource::New (StringArray const& strings)
{
return new StringsValidatorSourceImp (strings);
}

View File

@@ -1,31 +0,0 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
class TrustedUriValidatorSourceImp : public TrustedUriValidatorSource
{
public:
explicit TrustedUriValidatorSourceImp (String const url)
: m_url (url)
{
}
~TrustedUriValidatorSourceImp ()
{
}
Array <Validator::Info> fetch ()
{
return Array <Validator::Info> ();
}
private:
String const m_url;
};
TrustedUriValidatorSource* TrustedUriValidatorSource::New (String url)
{
return new TrustedUriValidatorSourceImp (url);
}

View File

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

View File

@@ -1,10 +0,0 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
#ifndef RIPPLE_VALIDATORLIST_H_INCLUDED
#define RIPPLE_VALIDATORLIST_H_INCLUDED
#endif

View File

@@ -1,451 +0,0 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
/*
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?
*/
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
};
//--------------------------------------------------------------------------
struct SourceInfo : LeakChecked <SourceInfo>
{
enum Status
{
statusNone,
statusFetched,
statusFailed,
};
explicit SourceInfo (Source* source_)
: source (source_)
, status (statusNone)
, numberOfFailures (0)
{
}
ScopedPointer <Source> const source;
Status status;
Time whenToFetch;
int numberOfFailures;
Validator::List::Ptr list;
};
//--------------------------------------------------------------------------
// Called during the list comparison
//
struct CompareCallback
{
virtual void onValidatorAdded (Validator const& validator) { }
virtual void onValidatorRemoved (Validator const& validator) { }
virtual void onValidatorUnchanged (Validator const& validator) { }
};
// Given the old list and the new list for a source, this
// computes which validators were added or removed, and
// updates some statistics.
//
static void compareLists (Validator::List const& oldList,
Validator::List const& newList,
CompareCallback& callback)
{
// Validator::List is always sorted so walk both arrays and
// do an element-wise comparison to perform set calculations.
//
int i = 0;
int j = 0;
while (i < oldList.size () || j < newList.size ())
{
if (i < oldList.size () && j < newList.size ())
{
int const compare = Validator::Compare::compareElements (
oldList [i], newList [j]);
if (compare < 0)
{
callback.onValidatorRemoved (*oldList [i]);
++i;
}
else if (compare > 0)
{
callback.onValidatorAdded (*newList [j]);
++j;
}
else
{
bassert (oldList [i] == newList [j]);
callback.onValidatorUnchanged (*newList [j]);
++i;
++j;
}
}
else if (i < oldList.size ())
{
callback.onValidatorRemoved (*oldList [i]);
++i;
}
else
{
bassert (j < newList.size ());
callback.onValidatorAdded (*newList [j]);
++j;
}
}
}
// Encapsulates the logic for creating the chosen validators.
// This is a separate class to facilitate the unit tests.
//
class Logic : public CompareCallback
{
private:
HashMap <Validator::PublicKey,
Validator::Ptr,
Validator::PublicKey::HashFunction> m_map;
OwnedArray <SourceInfo> m_sources;
public:
Logic ()
{
}
void addSource (Source* source)
{
m_sources.add (new SourceInfo (source));
}
OwnedArray <SourceInfo>& getSources ()
{
return m_sources;
}
void onValidatorAdded (Validator const& validator)
{
}
void onValidatorRemoved (Validator const& validator)
{
}
void onValidatorUnchanged (Validator const& validator)
{
}
// Produces an array of references to validators given the validator info.
//
Validator::List::Ptr createListFromInfo (Array <Validator::Info>& info)
{
Validator::Info::sortAndRemoveDuplicates (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.set (key, validator);
}
items.add (validator);
}
return new Validator::List (items);
}
// Fetch the validators from a source and process the result
//
void fetchAndProcessSource (SourceInfo& sourceInfo)
{
Array <Validator::Info> newInfo = sourceInfo.source->fetch ();
if (newInfo.size () != 0)
{
sourceInfo.status = SourceInfo::statusFetched;
sourceInfo.whenToFetch = Time::getCurrentTime () +
RelativeTime (hoursBetweenFetches * 60.0 * 60.0);
Validator::List::Ptr newList (createListFromInfo (newInfo));
compareLists (*sourceInfo.list, *newList, *this);
sourceInfo.list = newList;
}
else
{
// Failed to fetch, don't update fetch time
sourceInfo.status = SourceInfo::statusFailed;
sourceInfo.numberOfFailures++;
}
}
};
//--------------------------------------------------------------------------
public:
explicit ValidatorsImp (Validators::Listener* listener)
: m_listener (listener)
, m_thread ("Validators")
, m_timer (this)
{
m_thread.start (this);
}
~ValidatorsImp ()
{
}
void addSource (Source* source)
{
m_thread.call (&ValidatorsImp::doAddSource, this, source);
}
void doAddSource (Source* source)
{
m_logic.addSource (source);
}
void onDeadlineTimer (DeadlineTimer&)
{
// This will make us fall into the idle proc as needed
//
m_thread.interrupt ();
}
// Fetch sources whose deadline timers have arrived.
//
bool scanSources ()
{
bool interrupted = false;
for (int i = 0; i < m_logic.getSources ().size (); ++i)
{
SourceInfo& sourceInfo (*m_logic.getSources ()[i]);
Time const currentTime = Time::getCurrentTime ();
if (currentTime <= sourceInfo.whenToFetch)
{
m_logic.fetchAndProcessSource (sourceInfo);
}
interrupted = m_thread.interruptionPoint ();
if (interrupted)
break;
}
return interrupted;
}
void threadInit ()
{
m_timer.setRecurringExpiration (secondsPerUpdate);
}
void threadExit ()
{
}
bool threadIdle ()
{
bool interrupted = false;
interrupted = scanSources ();
return interrupted;
}
private:
Logic m_logic;
Validators::Listener* const m_listener;
ThreadWithCallQueue m_thread;
DeadlineTimer m_timer;
};
Validators* Validators::New (Listener* listener)
{
return new ValidatorsImp (listener);
}
//------------------------------------------------------------------------------
class ValidatorsTests : public UnitTest
{
public:
// Produces validators for unit tests.
class TestSource : public Validators::Source
{
public:
TestSource (unsigned int startIndex, unsigned int endIndex)
: m_startIndex (startIndex)
, m_endIndex (endIndex)
{
}
Array <Validator::Info> fetch ()
{
Array <Validator::Info> results;
for (unsigned int publicKeyIndex = m_startIndex; publicKeyIndex <= m_endIndex; ++publicKeyIndex)
{
Validator::Info info;
info.publicKey = Validator::PublicKey::createFromInteger (publicKeyIndex);
results.add (info);
}
return results;
}
private:
unsigned int const m_startIndex;
unsigned int const m_endIndex;
};
//--------------------------------------------------------------------------
struct TestCompareCallback : public ValidatorsImp::CompareCallback
{
int numTotal;
int numAdded;
int numRemoved;
int numUnchanged;
TestCompareCallback ()
: numTotal (0)
, numAdded (0)
, numRemoved (0)
, numUnchanged (0)
{
}
void onValidatorAdded (Validator const& validator)
{
++numTotal;
++numAdded;
}
void onValidatorRemoved (Validator const& validator)
{
++numTotal;
++numRemoved;
}
void onValidatorUnchanged (Validator const& validator)
{
++numTotal;
++numUnchanged;
}
};
//--------------------------------------------------------------------------
ValidatorsTests () : UnitTest ("Validators", "ripple", runManual)
{
}
// Check logic for comparing a source's fetch results
void testCompare ()
{
beginTestCase ("compare");
{
Array <Validator::Info> results = TestSource (1, 32).fetch ();
expect (results.size () == 32);
}
{
Array <Validator::Info> oldInfo = TestSource (1, 4).fetch ();
expect (oldInfo.size () == 4);
Array <Validator::Info> newInfo = TestSource (3, 6).fetch ();
expect (newInfo.size () == 4);
ValidatorsImp::Logic logic;
Validator::List::Ptr oldList = logic.createListFromInfo (oldInfo);
expect (oldList->size () == 4);
Validator::List::Ptr newList = logic.createListFromInfo (newInfo);
expect (newList->size () == 4);
TestCompareCallback cb;
ValidatorsImp::compareLists (*oldList, *newList, cb);
expect (cb.numAdded == 2);
expect (cb.numRemoved == 2);
expect (cb.numUnchanged == 2);
}
}
void runTest ()
{
testCompare ();
}
};
static ValidatorsTests validatorsTests;

View File

@@ -1,69 +0,0 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
#ifndef RIPPLE_VALIDATORS_H_INCLUDED
#define RIPPLE_VALIDATORS_H_INCLUDED
/** Maintains the list of chosen validators.
The algorithm for acquiring, building, and calculating metadata on
the list of chosen validators is critical to the health of the network.
All operations are performed asynchronously on an internal thread.
*/
class Validators : public Uncopyable
{
public:
/** Provides a ValidatorList.
*/
class Source
{
public:
/** Destroy the source.
If a fetch is active, it will be aborted before the
destructor returns.
*/
virtual ~Source () { }
/** Fetch the validator list from this source.
This call blocks.
*/
virtual Array <Validator::Info> fetch () =0;
};
//--------------------------------------------------------------------------
/** Receive event notifications on Validators operations.
*/
class Listener
{
public:
virtual void onValidatorsChosen (Validator::List::Ptr list) { }
};
//--------------------------------------------------------------------------
/** Create a new Validators object.
*/
static Validators* New (Listener* listener);
/** Destroy the object.
Any pending source fetch operations are aborted.
There may be some listener calls made before the
destructor returns.
*/
virtual ~Validators () { }
/** Add a source of validators.
*/
virtual void addSource (Source* source) = 0;
};
#endif