Move ./modules to ./src

This commit is contained in:
Vinnie Falco
2013-09-11 11:17:22 -07:00
parent 6d828ae476
commit 45eccf2ccf
386 changed files with 1673 additions and 1674 deletions

View File

@@ -0,0 +1,178 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
bool ParameterNode::setValue (const std::string& name, const Json::Value& value, Json::Value& error)
{
if (name.empty ()) // this node
return setValue (value, error);
size_t dot = name.find ('.');
if (dot == std::string::npos) // a child of this node
{
std::map<std::string, Parameter::pointer>::iterator it = mChildren.find (name);
if (it == mChildren.end ())
{
error = Json::objectValue;
error["error"] = "Name not found";
error["name"] = name;
return false;
}
return it->second->setValue (value, error);
}
std::map<std::string, Parameter::pointer>::iterator it = mChildren.find (name.substr (0, dot));
if (it == mChildren.end ())
{
error = Json::objectValue;
error["error"] = "Name not found";
error["name"] = name;
return false;
}
ParameterNode* n = dynamic_cast<ParameterNode*> (it->second.get ());
if (!n)
{
error = Json::objectValue;
error["error"] = "Node has no children";
error["name"] = it->second->getName ();
return false;
}
return n->setValue (name.substr (dot + 1), value, error);
}
bool ParameterNode::addNode (const std::string& name, Parameter::ref node)
{
if (name.empty ()) // this node
return false;
size_t dot = name.find ('.');
if (dot == std::string::npos) // a child of this node
{
std::map<std::string, Parameter::pointer>::iterator it = mChildren.find (name);
if (it != mChildren.end ())
return false;
mChildren[name] = node;
return true;
}
std::map<std::string, Parameter::pointer>::iterator it = mChildren.find (name.substr (0, dot));
ParameterNode* n;
if (it == mChildren.end ())
{
// create a new inner node
ParameterNode::pointer node = boost::make_shared<ParameterNode> (getShared (), name.substr (0, dot));
n = dynamic_cast<ParameterNode*> (node.get ());
assert (n);
mChildren[name] = node;
}
else
{
// existing node passed through must be inner
n = dynamic_cast<ParameterNode*> (it->second.get ());
if (!n)
return false;
}
return n->addNode (name.substr (dot + 1), node);
}
Json::Value ParameterNode::getValue (int i) const
{
Json::Value v (Json::objectValue);
typedef std::map<std::string, Parameter::pointer>::value_type string_ref_pair;
BOOST_FOREACH (const string_ref_pair & it, mChildren)
{
v[it.first] = it.second->getValue (i);
}
return v;
}
bool ParameterNode::setValue (const Json::Value& value, Json::Value& error)
{
error = Json::objectValue;
error["error"] = "Cannot end on an inner node";
Json::Value nodes (Json::arrayValue);
typedef std::map<std::string, Parameter::pointer>::value_type string_ref_pair;
BOOST_FOREACH (const string_ref_pair & it, mChildren)
{
nodes.append (it.first);
}
error["legal_nodes"] = nodes;
return false;
}
ParameterString::ParameterString (Parameter::ref parent, const std::string& name, const std::string& value)
: Parameter (parent, name), mValue (value)
{
;
}
Json::Value ParameterString::getValue (int) const
{
return Json::Value (mValue);
}
bool ParameterString::setValue (const Json::Value& value, Json::Value& error)
{
if (!value.isConvertibleTo (Json::stringValue))
{
error = Json::objectValue;
error["error"] = "Cannot convert to string";
error["value"] = value;
return false;
}
mValue = value.asString ();
return true;
}
ParameterInt::ParameterInt (Parameter::ref parent, const std::string& name, int value)
: Parameter (parent, name), mValue (value)
{
;
}
Json::Value ParameterInt::getValue (int) const
{
return Json::Value (mValue);
}
bool ParameterInt::setValue (const Json::Value& value, Json::Value& error)
{
if (value.isConvertibleTo (Json::intValue))
{
mValue = value.asInt ();
return true;
}
if (value.isConvertibleTo (Json::stringValue))
{
try
{
mValue = lexicalCastThrow <int> (value.asString ());
}
catch (...)
{
}
}
error = Json::objectValue;
error["error"] = "Cannot convert to integer";
error["value"] = value;
return false;
}

View File

@@ -0,0 +1,86 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
#ifndef RIPPLE_PARAMETERTABLE_H
#define RIPPLE_PARAMETERTABLE_H
class Parameter : public boost::enable_shared_from_this<Parameter>
{
// abstract base class parameters are derived from
public:
typedef boost::shared_ptr<Parameter> pointer;
typedef const boost::shared_ptr<Parameter>& ref;
public:
Parameter (Parameter::ref parent, const std::string& name) : mParent (parent), mName (name)
{
;
}
virtual ~Parameter ()
{
;
}
const std::string& getName () const
{
return mName;
}
virtual Json::Value getValue (int) const = 0;
virtual bool setValue (const Json::Value& value, Json::Value& error) = 0;
Parameter::pointer getShared ()
{
return shared_from_this ();
}
private:
pointer mParent;
std::string mName;
};
class ParameterNode : public Parameter
{
public:
ParameterNode (Parameter::ref parent, const std::string& name) : Parameter (parent, name)
{
;
}
bool addChildNode (Parameter::ref node);
bool setValue (const std::string& name, const Json::Value& value, Json::Value& error);
bool addNode (const std::string& name, Parameter::ref node);
virtual Json::Value getValue (int) const;
virtual bool setValue (const Json::Value& value, Json::Value& error);
private:
std::map<std::string, Parameter::pointer> mChildren;
};
class ParameterString : public Parameter
{
public:
ParameterString (Parameter::ref parent, const std::string& name, const std::string& value);
virtual Json::Value getValue (int) const;
virtual bool setValue (const Json::Value& value, Json::Value& error);
private:
std::string mValue;
};
class ParameterInt : public Parameter
{
public:
ParameterInt (Parameter::ref parent, const std::string& name, int value);
virtual Json::Value getValue (int) const;
virtual bool setValue (const Json::Value& value, Json::Value& error);
private:
int mValue;
};
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,123 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
#ifndef RIPPLE_IAPPLICATION_H
#define RIPPLE_IAPPLICATION_H
// VFALCO TODO Fix forward declares required for header dependency loops
class IFeatures;
class IFeeVote;
class IHashRouter;
class ILoadFeeTrack;
class Peers;
class UniqueNodeList;
class Validators;
class NodeStore;
class JobQueue;
class InboundLedgers;
class LedgerMaster;
class LoadManager;
class NetworkOPs;
class OrderBookDB;
class ProofOfWorkFactory;
class SerializedLedgerEntry;
class TransactionMaster;
class TxQueue;
class LocalCredentials;
class DatabaseCon;
typedef TaggedCacheType <uint256, Blob , UptimeTimerAdapter> NodeCache;
typedef TaggedCacheType <uint256, SerializedLedgerEntry, UptimeTimerAdapter> SLECache;
class Application
{
public:
/* VFALCO NOTE
The master lock protects:
- The open ledger
- Server global state
* What the last closed ledger is
* State of the consensus engine
other things
*/
typedef RippleRecursiveMutex LockType;
typedef LockType::ScopedLockType ScopedLockType;
virtual LockType& getMasterLock () = 0;
public:
struct State
{
// Stuff in here is accessed concurrently and requires a WriteAccess
};
typedef SharedData <State> SharedState;
SharedState& getSharedState () noexcept { return m_sharedState; }
SharedState const& getSharedState () const noexcept { return m_sharedState; }
private:
SharedState m_sharedState;
public:
virtual ~Application () { }
virtual boost::asio::io_service& getIOService () = 0;
virtual NodeCache& getTempNodeCache () = 0;
virtual SLECache& getSLECache () = 0;
virtual Validators& getValidators () = 0;
virtual IFeatures& getFeatureTable () = 0;
virtual IFeeVote& getFeeVote () = 0;
virtual IHashRouter& getHashRouter () = 0;
virtual ILoadFeeTrack& getFeeTrack () = 0;
virtual LoadManager& getLoadManager () = 0;
virtual Peers& getPeers () = 0;
virtual ProofOfWorkFactory& getProofOfWorkFactory () = 0;
virtual UniqueNodeList& getUNL () = 0;
virtual Validations& getValidations () = 0;
virtual NodeStore& getNodeStore () = 0;
virtual JobQueue& getJobQueue () = 0;
virtual InboundLedgers& getInboundLedgers () = 0;
virtual LedgerMaster& getLedgerMaster () = 0;
virtual NetworkOPs& getOPs () = 0;
virtual OrderBookDB& getOrderBookDB () = 0;
virtual TransactionMaster& getMasterTransaction () = 0;
virtual TxQueue& getTxQueue () = 0;
virtual LocalCredentials& getLocalCredentials () = 0;
virtual DatabaseCon* getRpcDB () = 0;
virtual DatabaseCon* getTxnDB () = 0;
virtual DatabaseCon* getLedgerDB () = 0;
/** Retrieve the "wallet database"
It looks like this is used to store the unique node list.
*/
// VFALCO TODO Rename, document this
// NOTE This will be replaced by class Validators
//
virtual DatabaseCon* getWalletDB () = 0;
virtual bool getSystemTimeOffset (int& offset) = 0;
virtual bool isShutdown () = 0;
virtual bool running () = 0;
virtual void setup () = 0;
virtual void run () = 0;
virtual void stop () = 0;
virtual void sweep () = 0;
};
extern Application& getApp ();
#endif

View File

@@ -0,0 +1,50 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
#ifdef TWICE
#error die
#endif
#define TWICE
FatalErrorReporter::FatalErrorReporter ()
{
FatalError::setReporter (*this);
}
FatalErrorReporter::~FatalErrorReporter ()
{
FatalError::resetReporter (*this);
}
void FatalErrorReporter::reportMessage (String& formattedMessage)
{
Log::out() << formattedMessage.toRawUTF8 ();
}
//------------------------------------------------------------------------------
class FatalErrorReporterTests : public UnitTest
{
public:
FatalErrorReporterTests () : UnitTest ("FatalErrorReporter", "ripple", runManual)
{
}
void runTest ()
{
beginTestCase ("report");
FatalErrorReporter reporter;
// We don't really expect the program to run after this
// but the unit test is here so you can manually test it.
FatalError ("The unit test intentionally failed", __FILE__, __LINE__);
}
};
static FatalErrorReporterTests fatalErrorReporterTests;

View File

@@ -0,0 +1,30 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
#ifndef RIPPLE_FATALERRORREPORTER_H_INCLUDED
#define RIPPLE_FATALERRORREPORTER_H_INCLUDED
/** FatalError reporter.
This writes the details to standard error and the log. The reporter is
installed for the lifetime of the object so typically you would put this
at the top of main().
An alternative is to make it a global variable but for this to cover all
possible cases, there can be no other global variables with non trivial
constructors that can report a fatal error. Also, the Log would need
to be guaranteed to be set up for this handler to work.
*/
class FatalErrorReporter : public FatalError::Reporter
{
public:
FatalErrorReporter ();
~FatalErrorReporter ();
void reportMessage (String& formattedMessage);
};
#endif

View File

@@ -0,0 +1,437 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
SETUP_LOG (LoadManager)
//------------------------------------------------------------------------------
class LoadManagerImp
: public LoadManager
, public beast::InterruptibleThread::EntryPoint
{
private:
/* Entry mapping utilization to cost.
The cost is expressed as a unitless relative quantity. These
mappings are statically loaded at startup with heuristic values.
*/
class Cost
{
public:
// VFALCO TODO Eliminate this default ctor somehow
Cost ()
: m_loadType ()
, m_cost (0)
, m_resourceFlags (0)
{
}
Cost (LoadType loadType, int cost, int resourceFlags)
: m_loadType (loadType)
, m_cost (cost)
, m_resourceFlags (resourceFlags)
{
}
LoadType getLoadType () const
{
return m_loadType;
}
int getCost () const
{
return m_cost;
}
int getResourceFlags () const
{
return m_resourceFlags;
}
public:
// VFALCO TODO Make these private and const
LoadType m_loadType;
int m_cost;
int m_resourceFlags;
};
public:
LoadManagerImp ()
: mLock (this, "LoadManagerImp", __FILE__, __LINE__)
, m_thread ("loadmgr")
, m_logThread ("loadmgr_log")
, mCreditRate (100)
, mCreditLimit (500)
, mDebitWarn (-500)
, mDebitLimit (-1000)
, mArmed (false)
, mDeadLock (0)
, mCosts (LT_MAX)
{
m_logThread.start ();
/** Flags indicating the type of load.
Utilization may include any combination of:
- CPU
- Storage space
- Network transfer
*/
// VFALCO NOTE These flags are not used...
enum
{
flagDisk = 1,
flagCpu = 2,
flagNet = 4
};
// VFALCO TODO Replace this with a function that uses a simple switch statement...
//
addCost (Cost (LT_InvalidRequest, -10, flagCpu | flagNet));
addCost (Cost (LT_RequestNoReply, -1, flagCpu | flagDisk));
addCost (Cost (LT_InvalidSignature, -100, flagCpu));
addCost (Cost (LT_UnwantedData, -5, flagCpu | flagNet));
addCost (Cost (LT_BadData, -20, flagCpu));
addCost (Cost (LT_RPCInvalid, -10, flagCpu | flagNet));
addCost (Cost (LT_RPCReference, -10, flagCpu | flagNet));
addCost (Cost (LT_RPCException, -20, flagCpu | flagNet));
addCost (Cost (LT_RPCBurden, -50, flagCpu | flagNet));
// VFALCO NOTE Why do these supposedly "good" load types still have a negative cost?
//
addCost (Cost (LT_NewTrusted, -10, 0));
addCost (Cost (LT_NewTransaction, -2, 0));
addCost (Cost (LT_NeededData, -10, 0));
addCost (Cost (LT_RequestData, -5, flagDisk | flagNet));
addCost (Cost (LT_CheapQuery, -1, flagCpu));
UptimeTimer::getInstance ().beginManualUpdates ();
}
private:
~LoadManagerImp ()
{
UptimeTimer::getInstance ().endManualUpdates ();
m_thread.interrupt ();
}
void startThread ()
{
m_thread.start (this);
}
void canonicalize (LoadSource& source, int now) const
{
if (source.mLastUpdate != now)
{
if (source.mLastUpdate < now)
{
source.mBalance += mCreditRate * (now - source.mLastUpdate);
if (source.mBalance > mCreditLimit)
{
source.mBalance = mCreditLimit;
source.mLogged = false;
}
}
source.mLastUpdate = now;
}
}
bool shouldWarn (LoadSource& source) const
{
{
ScopedLockType sl (mLock, __FILE__, __LINE__);
int now = UptimeTimer::getInstance ().getElapsedSeconds ();
canonicalize (source, now);
if (source.isPrivileged () || (source.mBalance > mDebitWarn) || (source.mLastWarning == now))
return false;
source.mLastWarning = now;
}
logWarning (source.getName ());
return true;
}
bool shouldCutoff (LoadSource& source) const
{
{
ScopedLockType sl (mLock, __FILE__, __LINE__);
int now = UptimeTimer::getInstance ().getElapsedSeconds ();
canonicalize (source, now);
if (source.isPrivileged () || (source.mBalance > mDebitLimit))
return false;
if (source.mLogged)
return true;
source.mLogged = true;
}
logDisconnect (source.getName ());
return true;
}
bool applyLoadCharge (LoadSource& source, LoadType loadType) const
{
// FIXME: Scale by category
Cost cost = mCosts[static_cast<int> (loadType)];
return adjust (source, cost.m_cost);
}
bool adjust (LoadSource& source, int credits) const
{
// return: true = need to warn/cutoff
// We do it this way in case we want to add exponential decay later
int now = UptimeTimer::getInstance ().getElapsedSeconds ();
ScopedLockType sl (mLock, __FILE__, __LINE__);
canonicalize (source, now);
source.mBalance += credits;
if (source.mBalance > mCreditLimit)
source.mBalance = mCreditLimit;
if (source.isPrivileged ()) // privileged sources never warn/cutoff
return false;
if ( (source.mBalance >= mDebitWarn) ||
((source.mBalance >= mDebitLimit) && (source.mLastWarning == now)))
return false;
return true;
}
void logWarning (const std::string& source) const
{
if (source.empty ())
WriteLog (lsDEBUG, LoadManager) << "Load warning from empty source";
else
WriteLog (lsINFO, LoadManager) << "Load warning: " << source;
}
void logDisconnect (const std::string& source) const
{
if (source.empty ())
WriteLog (lsINFO, LoadManager) << "Disconnect for empty source";
else
WriteLog (lsWARNING, LoadManager) << "Disconnect for: " << source;
}
// VFALCO TODO Implement this and stop accessing the vector directly
//Cost const& getCost (LoadType loadType) const;
int getCost (LoadType t) const
{
return mCosts [static_cast <int> (t)].getCost ();
}
void resetDeadlockDetector ()
{
ScopedLockType sl (mLock, __FILE__, __LINE__);
mDeadLock = UptimeTimer::getInstance ().getElapsedSeconds ();
}
void activateDeadlockDetector ()
{
mArmed = true;
}
static void logDeadlock (int dlTime)
{
WriteLog (lsWARNING, LoadManager) << "Server stalled for " << dlTime << " seconds.";
#if RIPPLE_TRACK_MUTEXES
StringArray report;
TrackedMutex::generateGlobalBlockedReport (report);
if (report.size () > 0)
{
report.insert (0, String::empty);
report.insert (-1, String::empty);
Log::print (report);
}
#endif
}
private:
// VFALCO TODO These used to be public but are apparently not used. Find out why.
/*
int getCreditRate () const
{
ScopedLockType sl (mLock, __FILE__, __LINE__);
return mCreditRate;
}
int getCreditLimit () const
{
ScopedLockType sl (mLock, __FILE__, __LINE__);
return mCreditLimit;
}
int getDebitWarn () const
{
ScopedLockType sl (mLock, __FILE__, __LINE__);
return mDebitWarn;
}
int getDebitLimit () const
{
ScopedLockType sl (mLock, __FILE__, __LINE__);
return mDebitLimit;
}
void setCreditRate (int r)
{
ScopedLockType sl (mLock, __FILE__, __LINE__);
mCreditRate = r;
}
void setCreditLimit (int r)
{
ScopedLockType sl (mLock, __FILE__, __LINE__);
mCreditLimit = r;
}
void setDebitWarn (int r)
{
ScopedLockType sl (mLock, __FILE__, __LINE__);
mDebitWarn = r;
}
void setDebitLimit (int r)
{
ScopedLockType sl (mLock, __FILE__, __LINE__);
mDebitLimit = r;
}
*/
private:
void addCost (const Cost& c)
{
mCosts [static_cast <int> (c.getLoadType ())] = c;
}
// VFALCO NOTE Where's the thread object? It's not a data member...
//
void threadRun ()
{
// VFALCO TODO replace this with a beast Time object?
//
// Initialize the clock to the current time.
boost::posix_time::ptime t = boost::posix_time::microsec_clock::universal_time ();
while (! m_thread.interruptionPoint ())
{
{
// VFALCO NOTE What is this lock protecting?
ScopedLockType sl (mLock, __FILE__, __LINE__);
// VFALCO NOTE I think this is to reduce calls to the operating system
// for retrieving the current time.
//
// TODO Instead of incrementing can't we just retrieve the current
// time again?
//
// Manually update the timer.
UptimeTimer::getInstance ().incrementElapsedTime ();
// Measure the amount of time we have been deadlocked, in seconds.
//
// VFALCO NOTE mDeadLock is a canary for detecting the condition.
int const timeSpentDeadlocked = UptimeTimer::getInstance ().getElapsedSeconds () - mDeadLock;
// VFALCO NOTE I think that "armed" refers to the deadlock detector
//
int const reportingIntervalSeconds = 10;
if (mArmed && (timeSpentDeadlocked >= reportingIntervalSeconds))
{
// Report the deadlocked condition every 10 seconds
if ((timeSpentDeadlocked % reportingIntervalSeconds) == 0)
{
// VFALCO TODO Replace this with a dedicated thread with call queue.
//
m_logThread.call (&logDeadlock, timeSpentDeadlocked);
}
// If we go over 500 seconds spent deadlocked, it means that the
// deadlock resolution code has failed, which qualifies as undefined
// behavior.
//
assert (timeSpentDeadlocked < 500);
}
}
bool change;
// VFALCO TODO Eliminate the dependence on the Application object.
// Choices include constructing with the job queue / feetracker.
// Another option is using an observer pattern to invert the dependency.
if (getApp().getJobQueue ().isOverloaded ())
{
WriteLog (lsINFO, LoadManager) << getApp().getJobQueue ().getJson (0);
change = getApp().getFeeTrack ().raiseLocalFee ();
}
else
{
change = getApp().getFeeTrack ().lowerLocalFee ();
}
if (change)
{
// VFALCO TODO replace this with a Listener / observer and subscribe in NetworkOPs or Application
getApp().getOPs ().reportFeeChange ();
}
t += boost::posix_time::seconds (1);
boost::posix_time::time_duration when = t - boost::posix_time::microsec_clock::universal_time ();
if ((when.is_negative ()) || (when.total_seconds () > 1))
{
WriteLog (lsWARNING, LoadManager) << "time jump";
t = boost::posix_time::microsec_clock::universal_time ();
}
else
{
boost::this_thread::sleep (when);
}
}
}
private:
typedef RippleMutex LockType;
typedef LockType::ScopedLockType ScopedLockType;
LockType mLock;
beast::InterruptibleThread m_thread;
beast::ThreadWithCallQueue m_logThread;
int mCreditRate; // credits gained/lost per second
int mCreditLimit; // the most credits a source can have
int mDebitWarn; // when a source drops below this, we warn
int mDebitLimit; // when a source drops below this, we cut it off (should be negative)
bool mArmed;
int mDeadLock; // Detect server deadlocks
std::vector <Cost> mCosts;
};
//------------------------------------------------------------------------------
LoadManager* LoadManager::New ()
{
ScopedPointer <LoadManager> object (new LoadManagerImp);
return object.release ();
}

View File

@@ -0,0 +1,87 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
#ifndef RIPPLE_LOADMANAGER_H_INCLUDEd
#define RIPPLE_LOADMANAGER_H_INCLUDEd
/** Manages load sources.
This object creates an associated thread to maintain a clock.
When the server is overloaded by a particular peer it issues a warning
first. This allows friendly peers to reduce their consumption of resources,
or disconnect from the server.
The warning system is used instead of merely dropping, because hostile
peers can just reconnect anyway.
@see LoadSource, LoadType
*/
class LoadManager
{
public:
/** Create a new manager.
The manager thread begins running immediately.
@note The thresholds for warnings and punishments are in
the ctor-initializer
*/
static LoadManager* New ();
/** Destroy the manager.
The destructor returns only after the thread has stopped.
*/
virtual ~LoadManager () { }
/** Start the associated thread.
This is here to prevent the deadlock detector from activating during
a lengthy program initialization.
*/
// VFALCO TODO Simplify the two stage initialization to one stage (construction).
// NOTE In stand-alone mode the load manager thread isn't started
virtual void startThread () = 0;
/** Turn on deadlock detection.
The deadlock detector begins in a disabled state. After this function
is called, it will report deadlocks using a separate thread whenever
the reset function is not called at least once per 10 seconds.
@see resetDeadlockDetector
*/
// VFALCO NOTE it seems that the deadlock detector has an "armed" state to prevent it
// from going off during program startup if there's a lengthy initialization
// operation taking place?
//
virtual void activateDeadlockDetector () = 0;
/** Reset the deadlock detection timer.
A dedicated thread monitors the deadlock timer, and if too much
time passes it will produce log warnings.
*/
virtual void resetDeadlockDetector () = 0;
/** Update an endpoint to reflect an imposed load.
The balance of the endpoint is adjusted based on the heuristic cost
of the indicated load.
@return `true` if the endpoint should be warned or punished.
*/
virtual bool applyLoadCharge (LoadSource& sourceToAdjust, LoadType loadToImpose) const = 0;
// VFALCO TODO Eliminate these two functions and just make applyLoadCharge()
// return a LoadSource::Disposition
//
virtual bool shouldWarn (LoadSource&) const = 0;
virtual bool shouldCutoff (LoadSource&) const = 0;
};
#endif

View File

@@ -0,0 +1,156 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
LocalCredentials::LocalCredentials ()
: mLedger (0)
{
}
void LocalCredentials::start ()
{
// We need our node identity before we begin networking.
// - Allows others to identify if they have connected multiple times.
// - Determines our CAS routing and responsibilities.
// - This is not our validation identity.
if (!nodeIdentityLoad ())
{
nodeIdentityCreate ();
if (!nodeIdentityLoad ())
throw std::runtime_error ("unable to retrieve new node identity.");
}
if (!getConfig ().QUIET)
Log::out() << "NodeIdentity: " << mNodePublicKey.humanNodePublic ();
getApp().getUNL ().start ();
}
// Retrieve network identity.
bool LocalCredentials::nodeIdentityLoad ()
{
Database* db = getApp().getWalletDB ()->getDB ();
DeprecatedScopedLock sl (getApp().getWalletDB ()->getDBLock ());
bool bSuccess = false;
if (db->executeSQL ("SELECT * FROM NodeIdentity;") && db->startIterRows ())
{
std::string strPublicKey, strPrivateKey;
db->getStr ("PublicKey", strPublicKey);
db->getStr ("PrivateKey", strPrivateKey);
mNodePublicKey.setNodePublic (strPublicKey);
mNodePrivateKey.setNodePrivate (strPrivateKey);
db->endIterRows ();
bSuccess = true;
}
if (getConfig ().NODE_PUB.isValid () && getConfig ().NODE_PRIV.isValid ())
{
mNodePublicKey = getConfig ().NODE_PUB;
mNodePrivateKey = getConfig ().NODE_PRIV;
}
return bSuccess;
}
// Create and store a network identity.
bool LocalCredentials::nodeIdentityCreate ()
{
if (!getConfig ().QUIET)
Log::out() << "NodeIdentity: Creating.";
//
// Generate the public and private key
//
RippleAddress naSeed = RippleAddress::createSeedRandom ();
RippleAddress naNodePublic = RippleAddress::createNodePublic (naSeed);
RippleAddress naNodePrivate = RippleAddress::createNodePrivate (naSeed);
// Make new key.
#ifdef CREATE_NEW_DH_PARAMS
std::string strDh512 = DH_der_gen (512);
#else
std::string strDh512 (RippleSSLContext::getRawDHParams (512));
#endif
#if 1
std::string strDh1024 = strDh512; // For testing and most cases 512 is fine.
#else
std::string strDh1024 = DH_der_gen (1024);
#endif
//
// Store the node information
//
Database* db = getApp().getWalletDB ()->getDB ();
DeprecatedScopedLock sl (getApp().getWalletDB ()->getDBLock ());
db->executeSQL (str (boost::format ("INSERT INTO NodeIdentity (PublicKey,PrivateKey,Dh512,Dh1024) VALUES ('%s','%s',%s,%s);")
% naNodePublic.humanNodePublic ()
% naNodePrivate.humanNodePrivate ()
% sqlEscape (strDh512)
% sqlEscape (strDh1024)));
// XXX Check error result.
if (!getConfig ().QUIET)
Log::out() << "NodeIdentity: Created.";
return true;
}
bool LocalCredentials::dataDelete (const std::string& strKey)
{
Database* db = getApp().getRpcDB ()->getDB ();
DeprecatedScopedLock sl (getApp().getRpcDB ()->getDBLock ());
return db->executeSQL (str (boost::format ("DELETE FROM RPCData WHERE Key=%s;")
% sqlEscape (strKey)));
}
bool LocalCredentials::dataFetch (const std::string& strKey, std::string& strValue)
{
Database* db = getApp().getRpcDB ()->getDB ();
DeprecatedScopedLock sl (getApp().getRpcDB ()->getDBLock ());
bool bSuccess = false;
if (db->executeSQL (str (boost::format ("SELECT Value FROM RPCData WHERE Key=%s;")
% sqlEscape (strKey))) && db->startIterRows ())
{
Blob vucData = db->getBinary ("Value");
strValue.assign (vucData.begin (), vucData.end ());
db->endIterRows ();
bSuccess = true;
}
return bSuccess;
}
bool LocalCredentials::dataStore (const std::string& strKey, const std::string& strValue)
{
Database* db = getApp().getRpcDB ()->getDB ();
DeprecatedScopedLock sl (getApp().getRpcDB ()->getDBLock ());
bool bSuccess = false;
return (db->executeSQL (str (boost::format ("REPLACE INTO RPCData (Key, Value) VALUES (%s,%s);")
% sqlEscape (strKey)
% sqlEscape (strValue)
)));
return bSuccess;
}
// vim:ts=4

View File

@@ -0,0 +1,55 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
#ifndef RIPPLE_LOCALCREDENTIALS_H
#define RIPPLE_LOCALCREDENTIALS_H
/** Holds the cryptographic credentials identifying this instance of the server.
*/
class LocalCredentials : public Uncopyable
{
public:
LocalCredentials ();
// Begin processing.
// - Maintain peer connectivity through validation and peer management.
void start ();
RippleAddress const& getNodePublic () const
{
return mNodePublicKey;
}
RippleAddress const& getNodePrivate () const
{
return mNodePrivateKey;
}
// Local persistence of RPC clients
bool dataDelete (std::string const& strKey);
// VFALCO NOTE why is strValue non-const?
bool dataFetch (std::string const& strKey, std::string& strValue);
bool dataStore (std::string const& strKey, std::string const& strValue);
private:
LocalCredentials (LocalCredentials const&); // disallowed
LocalCredentials& operator= (const LocalCredentials&); // disallowed
bool nodeIdentityLoad ();
bool nodeIdentityCreate ();
private:
boost::recursive_mutex mLock;
RippleAddress mNodePublicKey;
RippleAddress mNodePrivateKey;
LedgerIndex mLedger; // ledger we last synched to
};
#endif
// vim:ts=4

View File

@@ -0,0 +1,476 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
namespace po = boost::program_options;
void setupServer ()
{
#ifdef RLIMIT_NOFILE
struct rlimit rl;
if (getrlimit(RLIMIT_NOFILE, &rl) == 0)
{
if (rl.rlim_cur != rl.rlim_max)
{
rl.rlim_cur = rl.rlim_max;
setrlimit(RLIMIT_NOFILE, &rl);
}
}
#endif
getApp().setup ();
}
void startServer ()
{
//
// Execute start up rpc commands.
//
if (getConfig ().RPC_STARTUP.isArray ())
{
for (int i = 0; i != getConfig ().RPC_STARTUP.size (); ++i)
{
const Json::Value& jvCommand = getConfig ().RPC_STARTUP[i];
if (!getConfig ().QUIET)
Log::out() << "Startup RPC: " << jvCommand;
RPCHandler rhHandler (&getApp().getOPs ());
// VFALCO TODO Clean up this magic number
LoadType loadType = LT_RPCReference;
Json::Value jvResult = rhHandler.doCommand (jvCommand, Config::ADMIN, &loadType);
if (!getConfig ().QUIET)
Log::out() << "Result: " << jvResult;
}
}
getApp().run (); // Blocks till we get a stop RPC.
}
void printHelp (const po::options_description& desc)
{
using namespace std;
cerr << SYSTEM_NAME "d [options] <command> <params>" << endl;
cerr << desc << endl;
cerr << "Commands: " << endl;
cerr << " account_info <account>|<nickname>|<seed>|<pass_phrase>|<key> [<ledger>] [strict]" << endl;
cerr << " account_lines <account> <account>|\"\" [<ledger>]" << endl;
cerr << " account_offers <account>|<nickname>|<account_public_key> [<ledger>]" << endl;
cerr << " account_tx accountID [ledger_min [ledger_max [limit [offset]]]] [binary] [count] [descending]" << endl;
cerr << " book_offers <taker_pays> <taker_gets> [<taker [<ledger> [<limit> [<proof> [<marker>]]]]]" << endl;
cerr << " connect <ip> [<port>]" << endl;
cerr << " consensus_info" << endl;
#if ENABLE_INSECURE
cerr << " data_delete <key>" << endl;
cerr << " data_fetch <key>" << endl;
cerr << " data_store <key> <value>" << endl;
#endif
cerr << " get_counts" << endl;
cerr << " json <method> <json>" << endl;
cerr << " ledger [<id>|current|closed|validated] [full]" << endl;
cerr << " ledger_accept" << endl;
cerr << " ledger_closed" << endl;
cerr << " ledger_current" << endl;
cerr << " ledger_header <ledger>" << endl;
cerr << " logrotate " << endl;
cerr << " peers" << endl;
cerr << " proof_create [<difficulty>] [<secret>]" << endl;
cerr << " proof_solve <token>" << endl;
cerr << " proof_verify <token> <solution> [<difficulty>] [<secret>]" << endl;
cerr << " random" << endl;
cerr << " ripple ..." << endl;
cerr << " ripple_path_find <json> [<ledger>]" << endl;
// cerr << " send <seed> <paying_account> <account_id> <amount> [<currency>] [<send_max>] [<send_currency>]" << endl;
cerr << " stop" << endl;
cerr << " tx <id>" << endl;
cerr << " unl_add <domain>|<public> [<comment>]" << endl;
cerr << " unl_delete <domain>|<public_key>" << endl;
cerr << " unl_list" << endl;
cerr << " unl_load" << endl;
cerr << " unl_network" << endl;
cerr << " unl_reset" << endl;
cerr << " validation_create [<seed>|<pass_phrase>|<key>]" << endl;
cerr << " validation_seed [<seed>|<pass_phrase>|<key>]" << endl;
cerr << " wallet_add <regular_seed> <paying_account> <master_seed> [<initial_funds>] [<account_annotation>]" << endl;
cerr << " wallet_accounts <seed>" << endl;
cerr << " wallet_claim <master_seed> <regular_seed> [<source_tag>] [<account_annotation>]" << endl;
cerr << " wallet_seed [<seed>|<passphrase>|<passkey>]" << endl;
cerr << " wallet_propose [<passphrase>]" << endl;
// Transaction helpers (that were removed):
// cerr << " account_domain_set <seed> <paying_account> [<domain>]" << endl;
// cerr << " account_email_set <seed> <paying_account> [<email_address>]" << endl;
// cerr << " account_rate_set <seed> <paying_account> <rate>" << endl;
// cerr << " account_wallet_set <seed> <paying_account> [<wallet_hash>]" << endl;
// cerr << " nickname_info <nickname>" << endl;
// cerr << " nickname_set <seed> <paying_account> <nickname> [<offer_minimum>] [<authorization>]" << endl;
// cerr << " offer_create <seed> <paying_account> <taker_pays_amount> <taker_pays_currency> <taker_pays_issuer> <takers_gets_amount> <takers_gets_currency> <takers_gets_issuer> <expires> [passive]" << endl;
// cerr << " offer_cancel <seed> <paying_account> <sequence>" << endl;
// cerr << " password_fund <seed> <paying_account> [<account>]" << endl;
// cerr << " password_set <master_seed> <regular_seed> [<account>]" << endl;
// cerr << " trust_set <seed> <paying_account> <destination_account> <limit_amount> <currency> [<quality_in>] [<quality_out>]" << endl;
}
//------------------------------------------------------------------------------
// OUr custom unit test runner
//
class RippleUnitTests : public UnitTests
{
public:
explicit RippleUnitTests (bool shouldLog)
: m_shouldLog (shouldLog)
{
// VFALCO NOTE It sucks that we have to do this but some
// code demands the Application object exists.
//
// TODO To find out who, just change the #if 1 to #if 0
#if 1
setupConfigForUnitTests (&getConfig ());
getApp ();
#endif
setAssertOnFailure (false);
}
void logMessage (String const& message)
{
if (m_shouldLog)
{
#if BEAST_MSVC
if (beast_isRunningUnderDebugger ())
{
Logger::outputDebugString (message);
}
else
{
std::cout << message.toStdString () << std::endl;
}
#else
std::cout << message.toStdString () << std::endl;
#endif
}
}
private:
void setupConfigForUnitTests (Config* config)
{
config->nodeDatabase = parseDelimitedKeyValueString ("type=memory");
config->ephemeralNodeDatabase = StringPairArray ();
config->importNodeDatabase = StringPairArray ();
}
private:
bool const m_shouldLog;
};
static int runUnitTests (String const& match, String const& format)
{
bool const shouldLog = format != "junit";
if (format != "junit" && format != "text" && format != "")
{
String s;
s << "Warning, unknown unittest-format='" << format << "'";
Log::out () << s.toStdString ();
}
RippleUnitTests tr (shouldLog);
tr.runSelectedTests (match);
if (format == "junit")
{
UnitTestUtilities::JUnitXMLFormatter f (tr);
String const s = f.createDocumentString ();
std::cout << s.toStdString ();
}
else
{
UnitTests::Results const& r (tr.getResults ());
String s;
s << "Summary: " <<
String (r.suites.size ()) << " suites, " <<
String (r.cases) << " cases, " <<
String (r.tests) << " tests, " <<
String (r.failures) << " failure" << ((r.failures != 1) ? "s" : "") << ".";
tr.logMessage (s);
}
return tr.anyTestsFailed () ? EXIT_FAILURE : EXIT_SUCCESS;
}
//------------------------------------------------------------------------------
int RippleMain::run (int argc, char const* const* argv)
{
FatalErrorReporter reporter;
//
// These debug heap calls do nothing in release or non Visual Studio builds.
//
// Checks the heap at every allocation and deallocation (slow).
//
//Debug::setAlwaysCheckHeap (false);
// Keeps freed memory blocks and fills them with a guard value.
//
//Debug::setHeapDelayedFree (false);
// At exit, reports all memory blocks which have not been freed.
//
#if RIPPLE_DUMP_LEAKS_ON_EXIT
Debug::setHeapReportLeaks (true);
#else
Debug::setHeapReportLeaks (false);
#endif
#if 0
// This is some temporary leak checking test code
Debug::setHeapReportLeaks (false);
//malloc (512); // Any leaks before this line in the output are from static initializations.
ThreadWithCallQueue t ("test");
GlobalPagedFreeStore::getInstance ();
t.start ();
return 0;
#endif
using namespace std;
setCallingThreadName ("main");
int iResult = 0;
po::variables_map vm; // Map of options.
String importDescription;
{
importDescription <<
"Import an existing node database (specified in the " <<
"[" << ConfigSection::importNodeDatabase () << "] configuration file section) "
"into the current node database (specified in the " <<
"[" << ConfigSection::nodeDatabase () << "] configuration file section). ";
}
// VFALCO TODO Replace boost program options with something from Beast.
//
// Set up option parsing.
//
po::options_description desc ("General Options");
desc.add_options ()
("help,h", "Display this message.")
("conf", po::value<std::string> (), "Specify the configuration file.")
("rpc", "Perform rpc command (default).")
("rpc_ip", po::value <std::string> (), "Specify the IP address for RPC command. Format: <ip-address>[':'<port-number>]")
("rpc_port", po::value <int> (), "Specify the port number for RPC command.")
("standalone,a", "Run with no peers.")
("testnet,t", "Run in test net mode.")
("unittest,u", po::value <std::string> ()->implicit_value (""), "Perform unit tests.")
("unittest-format", po::value <std::string> ()->implicit_value ("text"), "Format unit test output. Choices are 'text', 'junit'")
("parameters", po::value< vector<string> > (), "Specify comma separated parameters.")
("quiet,q", "Reduce diagnotics.")
("verbose,v", "Verbose logging.")
("load", "Load the current ledger from the local DB.")
("replay","Replay a ledger close.")
("ledger", po::value<std::string> (), "Load the specified ledger and start from .")
("start", "Start from a fresh Ledger.")
("net", "Get the initial ledger from the network.")
("fg", "Run in the foreground.")
("import", importDescription.toStdString ().c_str ())
;
// Interpret positional arguments as --parameters.
po::positional_options_description p;
p.add ("parameters", -1);
// NOTE: These must be added before the
// Application object is created.
//
NodeStore::addAvailableBackends ();
// VFALCO NOTE SqliteBackendFactory is here because it has
// dependencies like SqliteDatabase and DatabaseCon
//
NodeStore::addBackendFactory (SqliteBackendFactory::getInstance ());
if (! RandomNumbers::getInstance ().initialize ())
{
Log::out() << "Unable to add system entropy";
iResult = 2;
}
if (iResult)
{
nothing ();
}
else
{
// Parse options, if no error.
try
{
po::store (po::command_line_parser (argc, argv)
.options (desc) // Parse options.
.positional (p) // Remainder as --parameters.
.run (),
vm);
po::notify (vm); // Invoke option notify functions.
}
catch (...)
{
iResult = 1;
}
}
if (iResult)
{
nothing ();
}
else if (vm.count ("help"))
{
iResult = 1;
}
// Use a watchdog process unless we're invoking a stand alone type of mode
//
if (HaveSustain ()
&& !iResult
&& !vm.count ("parameters")
&& !vm.count ("fg")
&& !vm.count ("standalone")
&& !vm.count ("unittest"))
{
std::string logMe = DoSustain (getConfig ().DEBUG_LOGFILE.string());
if (!logMe.empty ())
Log (lsWARNING) << logMe;
}
if (vm.count ("quiet"))
{
Log::setMinSeverity (lsFATAL, true);
}
else if (vm.count ("verbose"))
{
Log::setMinSeverity (lsTRACE, true);
}
else
{
Log::setMinSeverity (lsINFO, true);
}
// Run the unit tests if requested.
// The unit tests will exit the application with an appropriate return code.
//
if (vm.count ("unittest"))
{
String format;
if (vm.count ("unittest-format"))
format = vm ["unittest-format"].as <std::string> ();
return runUnitTests (vm ["unittest"].as <std::string> (), format);
}
if (!iResult)
{
getConfig ().setup (
vm.count ("conf") ? vm["conf"].as<std::string> () : "", // Config file.
!!vm.count ("testnet"), // Testnet flag.
!!vm.count ("quiet")); // Quiet flag.
if (vm.count ("standalone"))
{
getConfig ().RUN_STANDALONE = true;
getConfig ().LEDGER_HISTORY = 0;
}
}
if (vm.count ("start")) getConfig ().START_UP = Config::FRESH;
// Handle a one-time import option
//
if (vm.count ("import"))
{
String const optionString (vm ["import"].as <std::string> ());
getConfig ().importNodeDatabase = parseDelimitedKeyValueString (optionString);
}
if (vm.count ("ledger"))
{
getConfig ().START_LEDGER = vm["ledger"].as<std::string> ();
if (vm.count("replay"))
getConfig ().START_UP = Config::REPLAY;
else
getConfig ().START_UP = Config::LOAD;
}
else if (vm.count ("load"))
{
getConfig ().START_UP = Config::LOAD;
}
else if (vm.count ("net"))
{
getConfig ().START_UP = Config::NETWORK;
if (getConfig ().VALIDATION_QUORUM < 2)
getConfig ().VALIDATION_QUORUM = 2;
}
if (iResult == 0)
{
// These overrides must happen after the config file is loaded.
// Override the RPC destination IP address
//
if (vm.count ("rpc_ip"))
{
getConfig ().setRpcIpAndOptionalPort (vm ["rpc_ip"].as <std::string> ());
}
// Override the RPC destination port number
//
if (vm.count ("rpc_port"))
{
// VFALCO TODO This should be a short.
getConfig ().setRpcPort (vm ["rpc_port"].as <int> ());
}
}
if (iResult == 0)
{
if (!vm.count ("parameters"))
{
// No arguments. Run server.
setupServer ();
setCallingThreadName ("io");
startServer ();
}
else
{
// Have a RPC command.
setCallingThreadName ("rpc");
std::vector<std::string> vCmd = vm["parameters"].as<std::vector<std::string> > ();
iResult = RPCCall::fromCommandLine (vCmd);
}
}
if (1 == iResult && !vm.count ("quiet"))
printHelp (desc);
return iResult;
}

View File

@@ -0,0 +1,16 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
#ifndef RIPPLE_RIPPLEMAIN_H_INCLUDED
#define RIPPLE_RIPPLEMAIN_H_INCLUDED
class RippleMain : public Main
{
public:
int run (int argc, char const* const* argv);
};
#endif