mirror of
https://github.com/XRPLF/rippled.git
synced 2025-12-06 17:27:55 +00:00
Move ./modules to ./src
This commit is contained in:
3061
src/ripple_app/misc/NetworkOPs.cpp
Normal file
3061
src/ripple_app/misc/NetworkOPs.cpp
Normal file
File diff suppressed because it is too large
Load Diff
295
src/ripple_app/misc/NetworkOPs.h
Normal file
295
src/ripple_app/misc/NetworkOPs.h
Normal file
@@ -0,0 +1,295 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (c) 2011-2013, OpenCoin, Inc.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef RIPPLE_NETWORKOPS_H
|
||||
#define RIPPLE_NETWORKOPS_H
|
||||
|
||||
// Operations that clients may wish to perform against the network
|
||||
// Master operational handler, server sequencer, network tracker
|
||||
|
||||
class Peer;
|
||||
class LedgerConsensus;
|
||||
|
||||
// This is the primary interface into the "client" portion of the program.
|
||||
// Code that wants to do normal operations on the network such as
|
||||
// creating and monitoring accounts, creating transactions, and so on
|
||||
// should use this interface. The RPC code will primarily be a light wrapper
|
||||
// over this code.
|
||||
//
|
||||
// Eventually, it will check the node's operating mode (synched, unsynched,
|
||||
// etectera) and defer to the correct means of processing. The current
|
||||
// code assumes this node is synched (and will continue to do so until
|
||||
// there's a functional network.
|
||||
//
|
||||
/** Provides server functionality for clients.
|
||||
|
||||
Clients include backend applications, local commands, and connected
|
||||
clients. This class acts as a proxy, fulfilling the command with local
|
||||
data if possible, or asking the network and returning the results if
|
||||
needed.
|
||||
|
||||
A backend application or local client can trust a local instance of
|
||||
rippled / NetworkOPs. However, client software connecting to non-local
|
||||
instances of rippled will need to be hardened to protect against hostile
|
||||
or unreliable servers.
|
||||
*/
|
||||
class NetworkOPs : public InfoSub::Source
|
||||
{
|
||||
public:
|
||||
enum Fault
|
||||
{
|
||||
// exceptions these functions can throw
|
||||
IO_ERROR = 1,
|
||||
NO_NETWORK = 2,
|
||||
};
|
||||
|
||||
enum OperatingMode
|
||||
{
|
||||
// how we process transactions or account balance requests
|
||||
omDISCONNECTED = 0, // not ready to process requests
|
||||
omCONNECTED = 1, // convinced we are talking to the network
|
||||
omSYNCING = 2, // fallen slightly behind
|
||||
omTRACKING = 3, // convinced we agree with the network
|
||||
omFULL = 4 // we have the ledger and can even validate
|
||||
};
|
||||
|
||||
// VFALCO TODO Fix OrderBookDB to not need this unrelated type.
|
||||
//
|
||||
typedef boost::unordered_map <uint64, InfoSub::wptr> SubMapType;
|
||||
|
||||
public:
|
||||
// VFALCO TODO Make LedgerMaster a SharedPtr or a reference.
|
||||
//
|
||||
static NetworkOPs* New (LedgerMaster& ledgerMaster);
|
||||
|
||||
virtual ~NetworkOPs () { }
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
// Network information
|
||||
//
|
||||
|
||||
// Our best estimate of wall time in seconds from 1/1/2000
|
||||
virtual uint32 getNetworkTimeNC () = 0;
|
||||
// Our best estimate of current ledger close time
|
||||
virtual uint32 getCloseTimeNC () = 0;
|
||||
// Use *only* to timestamp our own validation
|
||||
virtual uint32 getValidationTimeNC () = 0;
|
||||
virtual void closeTimeOffset (int) = 0;
|
||||
virtual boost::posix_time::ptime getNetworkTimePT () = 0;
|
||||
virtual uint32 getLedgerID (uint256 const& hash) = 0;
|
||||
virtual uint32 getCurrentLedgerID () = 0;
|
||||
|
||||
virtual OperatingMode getOperatingMode () = 0;
|
||||
virtual std::string strOperatingMode () = 0;
|
||||
virtual Ledger::ref getClosedLedger () = 0;
|
||||
virtual Ledger::ref getValidatedLedger () = 0;
|
||||
virtual Ledger::ref getPublishedLedger () = 0;
|
||||
virtual Ledger::ref getCurrentLedger () = 0;
|
||||
virtual Ledger::ref getCurrentSnapshot () = 0;
|
||||
virtual Ledger::pointer getLedgerByHash (uint256 const& hash) = 0;
|
||||
virtual Ledger::pointer getLedgerBySeq (const uint32 seq) = 0;
|
||||
virtual void missingNodeInLedger (const uint32 seq) = 0;
|
||||
|
||||
virtual uint256 getClosedLedgerHash () = 0;
|
||||
|
||||
// Do we have this inclusive range of ledgers in our database
|
||||
virtual bool haveLedgerRange (uint32 from, uint32 to) = 0;
|
||||
virtual bool haveLedger (uint32 seq) = 0;
|
||||
virtual uint32 getValidatedSeq () = 0;
|
||||
virtual bool isValidated (uint32 seq) = 0;
|
||||
virtual bool isValidated (uint32 seq, uint256 const& hash) = 0;
|
||||
virtual bool isValidated (Ledger::ref l) = 0;
|
||||
virtual bool getValidatedRange (uint32& minVal, uint32& maxVal) = 0;
|
||||
virtual bool getFullValidatedRange (uint32& minVal, uint32& maxVal) = 0;
|
||||
|
||||
virtual SerializedValidation::ref getLastValidation () = 0;
|
||||
virtual void setLastValidation (SerializedValidation::ref v) = 0;
|
||||
virtual SLE::pointer getSLE (Ledger::pointer lpLedger, uint256 const& uHash) = 0;
|
||||
virtual SLE::pointer getSLEi (Ledger::pointer lpLedger, uint256 const& uHash) = 0;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
// Transaction processing
|
||||
//
|
||||
|
||||
// must complete immediately
|
||||
// VFALCO TODO Make this a TxCallback structure
|
||||
typedef FUNCTION_TYPE<void (Transaction::pointer, TER)> stCallback;
|
||||
virtual void submitTransaction (Job&, SerializedTransaction::pointer,
|
||||
stCallback callback = stCallback ()) = 0;
|
||||
virtual Transaction::pointer submitTransactionSync (Transaction::ref tpTrans,
|
||||
bool bAdmin, bool bFailHard, bool bSubmit) = 0;
|
||||
virtual void runTransactionQueue () = 0;
|
||||
virtual Transaction::pointer processTransaction (Transaction::pointer,
|
||||
bool bAdmin, bool bFailHard, stCallback) = 0;
|
||||
virtual Transaction::pointer processTransaction (Transaction::pointer transaction,
|
||||
bool bAdmin, bool bFailHard) = 0;
|
||||
virtual Transaction::pointer findTransactionByID (uint256 const& transactionID) = 0;
|
||||
virtual int findTransactionsByDestination (std::list<Transaction::pointer>&,
|
||||
const RippleAddress& destinationAccount, uint32 startLedgerSeq,
|
||||
uint32 endLedgerSeq, int maxTransactions) = 0;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
// Account functions
|
||||
//
|
||||
|
||||
virtual AccountState::pointer getAccountState (Ledger::ref lrLedger,
|
||||
const RippleAddress& accountID) = 0;
|
||||
virtual SLE::pointer getGenerator (Ledger::ref lrLedger,
|
||||
uint160 const& uGeneratorID) = 0;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
// Directory functions
|
||||
//
|
||||
|
||||
virtual STVector256 getDirNodeInfo (Ledger::ref lrLedger,
|
||||
uint256 const& uRootIndex, uint64& uNodePrevious, uint64& uNodeNext) = 0;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
// Owner functions
|
||||
//
|
||||
|
||||
virtual Json::Value getOwnerInfo (Ledger::pointer lpLedger,
|
||||
const RippleAddress& naAccount) = 0;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
// Book functions
|
||||
//
|
||||
|
||||
virtual void getBookPage (
|
||||
Ledger::pointer lpLedger,
|
||||
const uint160& uTakerPaysCurrencyID,
|
||||
const uint160& uTakerPaysIssuerID,
|
||||
const uint160& uTakerGetsCurrencyID,
|
||||
const uint160& uTakerGetsIssuerID,
|
||||
const uint160& uTakerID,
|
||||
const bool bProof,
|
||||
const unsigned int iLimit,
|
||||
const Json::Value& jvMarker,
|
||||
Json::Value& jvResult) = 0;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
// ledger proposal/close functions
|
||||
virtual void processTrustedProposal (LedgerProposal::pointer proposal,
|
||||
boost::shared_ptr<protocol::TMProposeSet> set, RippleAddress nodePublic,
|
||||
uint256 checkLedger, bool sigGood) = 0;
|
||||
|
||||
virtual SHAMapAddNode gotTXData (const boost::shared_ptr<Peer>& peer,
|
||||
uint256 const& hash, const std::list<SHAMapNode>& nodeIDs,
|
||||
const std::list< Blob >& nodeData) = 0;
|
||||
|
||||
virtual bool recvValidation (SerializedValidation::ref val,
|
||||
const std::string& source) = 0;
|
||||
|
||||
virtual void takePosition (int seq, SHAMap::ref position) = 0;
|
||||
|
||||
virtual SHAMap::pointer getTXMap (uint256 const& hash) = 0;
|
||||
|
||||
virtual bool hasTXSet (const boost::shared_ptr<Peer>& peer,
|
||||
uint256 const& set, protocol::TxSetStatus status) = 0;
|
||||
|
||||
virtual void mapComplete (uint256 const& hash, SHAMap::ref map) = 0;
|
||||
|
||||
virtual bool stillNeedTXSet (uint256 const& hash) = 0;
|
||||
|
||||
// Fetch packs
|
||||
virtual void makeFetchPack (Job&, boost::weak_ptr<Peer> peer,
|
||||
boost::shared_ptr<protocol::TMGetObjectByHash> request,
|
||||
Ledger::pointer wantLedger, Ledger::pointer haveLedger, uint32 uUptime) = 0;
|
||||
|
||||
virtual bool shouldFetchPack (uint32 seq) = 0;
|
||||
virtual void gotFetchPack (bool progress, uint32 seq) = 0;
|
||||
virtual void addFetchPack (uint256 const& hash, boost::shared_ptr< Blob >& data) = 0;
|
||||
virtual bool getFetchPack (uint256 const& hash, Blob& data) = 0;
|
||||
virtual int getFetchSize () = 0;
|
||||
virtual void sweepFetchPack () = 0;
|
||||
|
||||
// network state machine
|
||||
virtual void endConsensus (bool correctLCL) = 0;
|
||||
virtual void setStandAlone () = 0;
|
||||
virtual void setStateTimer () = 0;
|
||||
|
||||
virtual void newLCL (int proposers, int convergeTime, uint256 const& ledgerHash) = 0;
|
||||
// VFALCO TODO rename to setNeedNetworkLedger
|
||||
virtual void needNetworkLedger () = 0;
|
||||
virtual void clearNeedNetworkLedger () = 0;
|
||||
virtual bool isNeedNetworkLedger () = 0;
|
||||
virtual bool isFull () = 0;
|
||||
virtual void setProposing (bool isProposing, bool isValidating) = 0;
|
||||
virtual bool isProposing () = 0;
|
||||
virtual bool isValidating () = 0;
|
||||
virtual bool isFeatureBlocked () = 0;
|
||||
virtual void setFeatureBlocked () = 0;
|
||||
virtual void consensusViewChange () = 0;
|
||||
virtual int getPreviousProposers () = 0;
|
||||
virtual int getPreviousConvergeTime () = 0;
|
||||
virtual uint32 getLastCloseTime () = 0;
|
||||
virtual void setLastCloseTime (uint32 t) = 0;
|
||||
|
||||
virtual Json::Value getConsensusInfo () = 0;
|
||||
virtual Json::Value getServerInfo (bool human, bool admin) = 0;
|
||||
virtual void clearLedgerFetch () = 0;
|
||||
virtual Json::Value getLedgerFetchInfo () = 0;
|
||||
virtual uint32 acceptLedger () = 0;
|
||||
|
||||
typedef boost::unordered_map <uint160, std::list<LedgerProposal::pointer> > Proposals;
|
||||
virtual Proposals& peekStoredProposals () = 0;
|
||||
|
||||
virtual void storeProposal (LedgerProposal::ref proposal,
|
||||
const RippleAddress& peerPublic) = 0;
|
||||
|
||||
virtual uint256 getConsensusLCL () = 0;
|
||||
|
||||
virtual void reportFeeChange () = 0;
|
||||
|
||||
//Helper function to generate SQL query to get transactions
|
||||
virtual std::string transactionsSQL (std::string selection,
|
||||
const RippleAddress& account, int32 minLedger, int32 maxLedger,
|
||||
bool descending, uint32 offset, int limit, bool binary,
|
||||
bool count, bool bAdmin) = 0;
|
||||
|
||||
// client information retrieval functions
|
||||
typedef std::vector< std::pair<Transaction::pointer, TransactionMetaSet::pointer> > AccountTxs;
|
||||
virtual AccountTxs getAccountTxs (const RippleAddress& account,
|
||||
int32 minLedger, int32 maxLedger, bool descending, uint32 offset,
|
||||
int limit, bool bAdmin) = 0;
|
||||
|
||||
typedef std::vector< std::pair<Transaction::pointer, TransactionMetaSet::pointer> > TxsAccount;
|
||||
virtual TxsAccount getTxsAccount (const RippleAddress& account,
|
||||
int32 minLedger, int32 maxLedger, bool forward, Json::Value& token,
|
||||
int limit, bool bAdmin) = 0;
|
||||
|
||||
typedef boost::tuple<std::string, std::string, uint32> txnMetaLedgerType;
|
||||
typedef std::vector<txnMetaLedgerType> MetaTxsList;
|
||||
virtual MetaTxsList getAccountTxsB (const RippleAddress& account,
|
||||
int32 minLedger, int32 maxLedger, bool descending,
|
||||
uint32 offset, int limit, bool bAdmin) = 0;
|
||||
|
||||
virtual MetaTxsList getTxsAccountB (const RippleAddress& account,
|
||||
int32 minLedger, int32 maxLedger, bool forward,
|
||||
Json::Value& token, int limit, bool bAdmin) = 0;
|
||||
|
||||
virtual std::vector<RippleAddress> getLedgerAffectedAccounts (uint32 ledgerSeq) = 0;
|
||||
|
||||
virtual uint32 countAccountTxs (const RippleAddress& account,
|
||||
int32 minLedger, int32 maxLedger) = 0;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
// Monitoring: publisher side
|
||||
//
|
||||
virtual void pubLedger (Ledger::ref lpAccepted) = 0;
|
||||
virtual void pubProposedTransaction (Ledger::ref lpCurrent,
|
||||
SerializedTransaction::ref stTxn, TER terResult) = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
20
src/ripple_app/misc/PowResult.h
Normal file
20
src/ripple_app/misc/PowResult.h
Normal file
@@ -0,0 +1,20 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (c) 2011-2013, OpenCoin, Inc.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef RIPPLE_POWRESULT_H_INCLUDED
|
||||
#define RIPPLE_POWRESULT_H_INCLUDED
|
||||
|
||||
enum PowResult
|
||||
{
|
||||
powOK = 0,
|
||||
powREUSED = 1, // already submitted
|
||||
powBADNONCE = 2, // you didn't solve it
|
||||
powEXPIRED = 3, // time is up
|
||||
powCORRUPT = 4,
|
||||
powTOOEASY = 5, // the difficulty increased too much while you solved it
|
||||
};
|
||||
|
||||
#endif
|
||||
179
src/ripple_app/misc/ProofOfWork.cpp
Normal file
179
src/ripple_app/misc/ProofOfWork.cpp
Normal file
@@ -0,0 +1,179 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (c) 2011-2013, OpenCoin, Inc.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
SETUP_LOG (ProofOfWork)
|
||||
|
||||
// VFALCO TODO Move these to a header
|
||||
const uint256 ProofOfWork::sMinTarget ("00000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF");
|
||||
|
||||
ProofOfWork::ProofOfWork (const std::string& token,
|
||||
int iterations,
|
||||
uint256 const& challenge,
|
||||
uint256 const& target)
|
||||
: mToken (token)
|
||||
, mChallenge (challenge)
|
||||
, mTarget (target)
|
||||
, mIterations (iterations)
|
||||
{
|
||||
}
|
||||
|
||||
ProofOfWork::ProofOfWork (const std::string& token)
|
||||
{
|
||||
std::vector<std::string> fields;
|
||||
boost::split (fields, token, boost::algorithm::is_any_of ("-"));
|
||||
|
||||
if (fields.size () != 5)
|
||||
throw std::runtime_error ("invalid token");
|
||||
|
||||
mToken = token;
|
||||
mChallenge.SetHex (fields[0]);
|
||||
mTarget.SetHex (fields[1]);
|
||||
mIterations = lexicalCast <int> (fields[2]);
|
||||
}
|
||||
|
||||
bool ProofOfWork::isValid () const
|
||||
{
|
||||
if ((mIterations <= kMaxIterations) && (mTarget >= sMinTarget))
|
||||
return true;
|
||||
|
||||
WriteLog (lsWARNING, ProofOfWork) << "Invalid PoW: " << mIterations << ", " << mTarget;
|
||||
return false;
|
||||
}
|
||||
|
||||
uint64 ProofOfWork::getDifficulty (uint256 const& target, int iterations)
|
||||
{
|
||||
// calculate the approximate number of hashes required to solve this proof of work
|
||||
if ((iterations > kMaxIterations) || (target < sMinTarget))
|
||||
{
|
||||
WriteLog (lsINFO, ProofOfWork) << "Iterations:" << iterations;
|
||||
WriteLog (lsINFO, ProofOfWork) << "MaxIterat: " << kMaxIterations;
|
||||
WriteLog (lsINFO, ProofOfWork) << "Target: " << target;
|
||||
WriteLog (lsINFO, ProofOfWork) << "MinTarget: " << sMinTarget;
|
||||
throw std::runtime_error ("invalid proof of work target/iteration");
|
||||
}
|
||||
|
||||
// more iterations means more hashes per iteration but also a larger final hash
|
||||
uint64 difficulty = iterations + (iterations / 8);
|
||||
|
||||
// Multiply the number of hashes needed by 256 for each leading zero byte in the difficulty
|
||||
const unsigned char* ptr = target.begin ();
|
||||
|
||||
while (*ptr == 0)
|
||||
{
|
||||
difficulty *= 256;
|
||||
++ptr;
|
||||
}
|
||||
|
||||
difficulty = (difficulty * 256) / (*ptr + 1);
|
||||
|
||||
return difficulty;
|
||||
}
|
||||
|
||||
static uint256 getSHA512Half (const std::vector<uint256>& vec)
|
||||
{
|
||||
return Serializer::getSHA512Half (vec.front ().begin (), vec.size () * (256 / 8));
|
||||
}
|
||||
|
||||
uint256 ProofOfWork::solve (int maxIterations) const
|
||||
{
|
||||
if (!isValid ())
|
||||
throw std::runtime_error ("invalid proof of work target/iteration");
|
||||
|
||||
uint256 nonce;
|
||||
RandomNumbers::getInstance ().fill (&nonce);
|
||||
|
||||
std::vector<uint256> buf2;
|
||||
buf2.resize (mIterations);
|
||||
|
||||
std::vector<uint256> buf1;
|
||||
buf1.resize (3);
|
||||
buf1[0] = mChallenge;
|
||||
|
||||
while (maxIterations > 0)
|
||||
{
|
||||
buf1[1] = nonce;
|
||||
buf1[2].zero ();
|
||||
|
||||
for (int i = (mIterations - 1); i >= 0; --i)
|
||||
{
|
||||
buf1[2] = getSHA512Half (buf1);
|
||||
buf2[i] = buf1[2];
|
||||
}
|
||||
|
||||
if (getSHA512Half (buf2) <= mTarget)
|
||||
return nonce;
|
||||
|
||||
++nonce;
|
||||
--maxIterations;
|
||||
}
|
||||
|
||||
return uint256 ();
|
||||
}
|
||||
|
||||
bool ProofOfWork::checkSolution (uint256 const& solution) const
|
||||
{
|
||||
if (mIterations > kMaxIterations)
|
||||
return false;
|
||||
|
||||
std::vector<uint256> buf1;
|
||||
buf1.push_back (mChallenge);
|
||||
buf1.push_back (solution);
|
||||
buf1.push_back (uint256 ());
|
||||
|
||||
std::vector<uint256> buf2;
|
||||
buf2.resize (mIterations);
|
||||
|
||||
for (int i = (mIterations - 1); i >= 0; --i)
|
||||
{
|
||||
buf1[2] = getSHA512Half (buf1);
|
||||
buf2[i] = buf1[2];
|
||||
}
|
||||
|
||||
return getSHA512Half (buf2) <= mTarget;
|
||||
}
|
||||
|
||||
bool ProofOfWork::validateToken (const std::string& strToken)
|
||||
{
|
||||
static boost::regex reToken ("[[:xdigit:]]{64}-[[:xdigit:]]{64}-[[:digit:]]+-[[:digit:]]+-[[:xdigit:]]{64}");
|
||||
boost::smatch smMatch;
|
||||
|
||||
return boost::regex_match (strToken, smMatch, reToken);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
bool ProofOfWork::calcResultInfo (PowResult powCode, std::string& strToken, std::string& strHuman)
|
||||
{
|
||||
static struct
|
||||
{
|
||||
PowResult powCode;
|
||||
const char* cpToken;
|
||||
const char* cpHuman;
|
||||
} powResultInfoA[] =
|
||||
{
|
||||
{ powREUSED, "powREUSED", "Proof-of-work has already been used." },
|
||||
{ powBADNONCE, "powBADNONCE", "The solution does not meet the required difficulty." },
|
||||
{ powEXPIRED, "powEXPIRED", "Token is expired." },
|
||||
{ powCORRUPT, "powCORRUPT", "Invalid token." },
|
||||
{ powTOOEASY, "powTOOEASY", "Difficulty has increased since token was issued." },
|
||||
|
||||
{ powOK, "powOK", "Valid proof-of-work." },
|
||||
};
|
||||
|
||||
int iIndex = NUMBER (powResultInfoA);
|
||||
|
||||
while (iIndex-- && powResultInfoA[iIndex].powCode != powCode)
|
||||
;
|
||||
|
||||
if (iIndex >= 0)
|
||||
{
|
||||
strToken = powResultInfoA[iIndex].cpToken;
|
||||
strHuman = powResultInfoA[iIndex].cpHuman;
|
||||
}
|
||||
|
||||
return iIndex >= 0;
|
||||
}
|
||||
|
||||
65
src/ripple_app/misc/ProofOfWork.h
Normal file
65
src/ripple_app/misc/ProofOfWork.h
Normal file
@@ -0,0 +1,65 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (c) 2011-2013, OpenCoin, Inc.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef RIPPLE_PROOFOFWORK_H
|
||||
#define RIPPLE_PROOFOFWORK_H
|
||||
|
||||
class ProofOfWork : LeakChecked <ProofOfWork>
|
||||
{
|
||||
public:
|
||||
enum
|
||||
{
|
||||
kMaxIterations = (1 << 23)
|
||||
};
|
||||
|
||||
typedef boost::shared_ptr <ProofOfWork> pointer;
|
||||
|
||||
ProofOfWork (const std::string& token,
|
||||
int iterations,
|
||||
uint256 const& challenge,
|
||||
uint256 const& target);
|
||||
|
||||
explicit ProofOfWork (const std::string& token);
|
||||
|
||||
bool isValid () const;
|
||||
|
||||
uint256 solve (int maxIterations = 2 * kMaxIterations) const;
|
||||
bool checkSolution (uint256 const& solution) const;
|
||||
|
||||
const std::string& getToken () const
|
||||
{
|
||||
return mToken;
|
||||
}
|
||||
uint256 const& getChallenge () const
|
||||
{
|
||||
return mChallenge;
|
||||
}
|
||||
|
||||
uint64 getDifficulty () const
|
||||
{
|
||||
return getDifficulty (mTarget, mIterations);
|
||||
}
|
||||
|
||||
// approximate number of hashes needed to solve
|
||||
static uint64 getDifficulty (uint256 const& target, int iterations);
|
||||
|
||||
static bool validateToken (const std::string& strToken);
|
||||
|
||||
static bool calcResultInfo (PowResult powCode, std::string& strToken, std::string& strHuman);
|
||||
|
||||
private:
|
||||
std::string mToken;
|
||||
uint256 mChallenge;
|
||||
uint256 mTarget;
|
||||
int mIterations;
|
||||
|
||||
static const uint256 sMinTarget;
|
||||
static const int maxIterations;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
// vim:ts=4
|
||||
411
src/ripple_app/misc/ProofOfWorkFactory.cpp
Normal file
411
src/ripple_app/misc/ProofOfWorkFactory.cpp
Normal file
@@ -0,0 +1,411 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (c) 2011-2013, OpenCoin, Inc.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
class ProofOfWorkFactoryImp
|
||||
: public ProofOfWorkFactory
|
||||
, public LeakChecked <ProofOfWorkFactoryImp>
|
||||
{
|
||||
public:
|
||||
typedef boost::bimap< boost::bimaps::multiset_of<time_t>,
|
||||
boost::bimaps::unordered_set_of<uint256> > powMap_t;
|
||||
|
||||
typedef powMap_t::value_type powMap_vt;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
ProofOfWorkFactoryImp ()
|
||||
: mLock (this, "PoWFactory", __FILE__, __LINE__)
|
||||
, mValidTime (180)
|
||||
{
|
||||
setDifficulty (1);
|
||||
RandomNumbers::getInstance ().fillBytes (mSecret.begin (), mSecret.size ());
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
enum
|
||||
{
|
||||
numPowEntries = kMaxDifficulty + 1
|
||||
};
|
||||
|
||||
struct PowEntry
|
||||
{
|
||||
const char* target;
|
||||
int iterations;
|
||||
};
|
||||
|
||||
typedef std::vector <PowEntry> PowEntries;
|
||||
|
||||
static PowEntries const& getPowEntries ()
|
||||
{
|
||||
struct StaticPowEntries
|
||||
{
|
||||
StaticPowEntries ()
|
||||
{
|
||||
// VFALCO TODO Make this array know its own size.
|
||||
//
|
||||
PowEntry entries [numPowEntries] =
|
||||
{
|
||||
// target iterations hashes memory
|
||||
{ "0CFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 65536 }, // 1451874, 2 MB
|
||||
{ "0CFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 98304 }, // 2177811, 3 MB
|
||||
{ "07FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 98304 }, // 3538944, 3 MB
|
||||
{ "0CFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 196608}, // 4355623, 6 MB
|
||||
|
||||
{ "07FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 131072}, // 4718592, 4 MB
|
||||
{ "0CFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 262144}, // 5807497, 8 MB
|
||||
{ "07FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 196608}, // 7077888, 6 MB
|
||||
{ "07FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 262144}, // 9437184, 8 MB
|
||||
|
||||
{ "07FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 393216}, // 14155776, 12MB
|
||||
{ "03FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 393216}, // 28311552, 12MB
|
||||
{ "00CFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 262144}, // 92919965, 8 MB
|
||||
{ "00CFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 393216}, // 139379948, 12MB
|
||||
|
||||
{ "007FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 262144}, // 150994944, 8 MB
|
||||
{ "007FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 393216}, // 226492416, 12MB
|
||||
{ "000CFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 49152 }, // 278759896, 1.5MB
|
||||
{ "003FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 262144}, // 301989888, 8 MB
|
||||
|
||||
{ "003FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 393216}, // 452984832, 12MB
|
||||
{ "0007FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 98304 }, // 905969664, 3 MB
|
||||
{ "000CFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 196608}, // 1115039586, 6 MB
|
||||
{ "000CFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 262144}, // 1486719448 8 MB
|
||||
|
||||
{ "000CFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 393216}, // 2230079172 12MB
|
||||
{ "0007FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 262144}, // 2415919104, 8 MB
|
||||
{ "0007FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 393216}, // 3623878656, 12MB
|
||||
{ "0003FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 393216}, // 7247757312, 12MB
|
||||
|
||||
{ "0000CFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 262144}, // 23787511177, 8 MB
|
||||
{ "0000CFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 393216}, // 35681266766, 12MB
|
||||
{ "00003FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 131072}, // 38654705664, 4 MB
|
||||
{ "00007FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 262144}, // 38654705664, 8 MB
|
||||
|
||||
{ "00003FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 196608}, // 57982058496, 6 MB
|
||||
{ "00007FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 393216}, // 57982058496, 12MB
|
||||
{ "00003FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 262144}, // 77309411328, 8 MB
|
||||
};
|
||||
|
||||
data.reserve (numPowEntries);
|
||||
|
||||
for (int i = 0; i < numPowEntries; ++i)
|
||||
data.push_back (entries [i]);
|
||||
}
|
||||
|
||||
std::vector <PowEntry> data;
|
||||
};
|
||||
|
||||
static StaticPowEntries list;
|
||||
|
||||
return list.data;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
static int getPowEntry (uint256 const& target, int iterations)
|
||||
{
|
||||
PowEntries const& entries (getPowEntries ());
|
||||
|
||||
for (int i = 0; i < numPowEntries; ++i)
|
||||
{
|
||||
if (entries [i].iterations == iterations)
|
||||
{
|
||||
uint256 t;
|
||||
t.SetHex (entries [i].target);
|
||||
|
||||
if (t == target)
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
ProofOfWork getProof ()
|
||||
{
|
||||
// challenge - target - iterations - time - validator
|
||||
static boost::format f ("%s-%s-%d-%d");
|
||||
|
||||
int now = static_cast<int> (time (NULL) / 4);
|
||||
|
||||
uint256 challenge;
|
||||
RandomNumbers::getInstance ().fillBytes (challenge.begin (), challenge.size ());
|
||||
|
||||
ScopedLockType sl (mLock, __FILE__, __LINE__);
|
||||
|
||||
std::string s = boost::str (boost::format (f) % challenge.GetHex () % mTarget.GetHex () % mIterations % now);
|
||||
std::string c = mSecret.GetHex () + s;
|
||||
s += "-" + Serializer::getSHA512Half (c).GetHex ();
|
||||
|
||||
return ProofOfWork (s, mIterations, challenge, mTarget);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
PowResult checkProof (const std::string& token, uint256 const& solution)
|
||||
{
|
||||
// VFALCO COmmented this out because Dave said it wasn't used
|
||||
// and also we dont have the lexicalCast from a vector of strings to a time_t
|
||||
|
||||
// challenge - target - iterations - time - validator
|
||||
|
||||
std::vector<std::string> fields;
|
||||
boost::split (fields, token, boost::algorithm::is_any_of ("-"));
|
||||
|
||||
if (fields.size () != 5)
|
||||
{
|
||||
WriteLog (lsDEBUG, ProofOfWork) << "PoW " << token << " is corrupt";
|
||||
return powCORRUPT;
|
||||
}
|
||||
|
||||
std::string v = mSecret.GetHex () + fields[0] + "-" + fields[1] + "-" + fields[2] + "-" + fields[3];
|
||||
|
||||
if (fields[4] != Serializer::getSHA512Half (v).GetHex ())
|
||||
{
|
||||
WriteLog (lsDEBUG, ProofOfWork) << "PoW " << token << " has a bad token";
|
||||
return powCORRUPT;
|
||||
}
|
||||
|
||||
uint256 challenge, target;
|
||||
challenge.SetHex (fields[0]);
|
||||
target.SetHex (fields[1]);
|
||||
|
||||
time_t t;
|
||||
#if 0
|
||||
// Broken with lexicalCast<> changes
|
||||
t = lexicalCast <time_t> (fields[3]);
|
||||
#else
|
||||
t = static_cast <time_t> (lexicalCast <uint64> (fields [3]));
|
||||
#endif
|
||||
|
||||
time_t now = time (NULL);
|
||||
|
||||
int iterations = lexicalCast <int> (fields[2]);
|
||||
|
||||
{
|
||||
ScopedLockType sl (mLock, __FILE__, __LINE__);
|
||||
|
||||
if ((t * 4) > (now + mValidTime))
|
||||
{
|
||||
WriteLog (lsDEBUG, ProofOfWork) << "PoW " << token << " has expired";
|
||||
return powEXPIRED;
|
||||
}
|
||||
|
||||
if (((iterations != mIterations) || (target != mTarget)) && getPowEntry (target, iterations) < (mPowEntry - 2))
|
||||
{
|
||||
// difficulty has increased more than two times since PoW requested
|
||||
WriteLog (lsINFO, ProofOfWork) << "Difficulty has increased since PoW requested";
|
||||
return powTOOEASY;
|
||||
}
|
||||
}
|
||||
|
||||
ProofOfWork pow (token, iterations, challenge, target);
|
||||
|
||||
if (!pow.checkSolution (solution))
|
||||
{
|
||||
WriteLog (lsDEBUG, ProofOfWork) << "PoW " << token << " has a bad nonce";
|
||||
return powBADNONCE;
|
||||
}
|
||||
|
||||
{
|
||||
ScopedLockType sl (mLock, __FILE__, __LINE__);
|
||||
|
||||
if (!mSolvedChallenges.insert (powMap_vt (now, challenge)).second)
|
||||
{
|
||||
WriteLog (lsDEBUG, ProofOfWork) << "PoW " << token << " has been reused";
|
||||
return powREUSED;
|
||||
}
|
||||
}
|
||||
|
||||
return powOK;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
void sweep ()
|
||||
{
|
||||
time_t expire = time (NULL) - mValidTime;
|
||||
|
||||
ScopedLockType sl (mLock, __FILE__, __LINE__);
|
||||
|
||||
do
|
||||
{
|
||||
powMap_t::left_map::iterator it = mSolvedChallenges.left.begin ();
|
||||
|
||||
if (it == mSolvedChallenges.left.end ())
|
||||
return;
|
||||
|
||||
if (it->first >= expire)
|
||||
return;
|
||||
|
||||
mSolvedChallenges.left.erase (it);
|
||||
}
|
||||
while (1);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
void loadHigh ()
|
||||
{
|
||||
time_t now = time (NULL);
|
||||
|
||||
ScopedLockType sl (mLock, __FILE__, __LINE__);
|
||||
|
||||
if (mLastDifficultyChange == now)
|
||||
return;
|
||||
|
||||
if (mPowEntry == 30)
|
||||
return;
|
||||
|
||||
++mPowEntry;
|
||||
mLastDifficultyChange = now;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
void loadLow ()
|
||||
{
|
||||
time_t now = time (NULL);
|
||||
|
||||
ScopedLockType sl (mLock, __FILE__, __LINE__);
|
||||
|
||||
if (mLastDifficultyChange == now)
|
||||
return;
|
||||
|
||||
if (mPowEntry == 0)
|
||||
return;
|
||||
|
||||
--mPowEntry;
|
||||
mLastDifficultyChange = now;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
void setDifficulty (int i)
|
||||
{
|
||||
assert ((i >= 0) && (i <= kMaxDifficulty));
|
||||
time_t now = time (NULL);
|
||||
|
||||
ScopedLockType sl (mLock, __FILE__, __LINE__);
|
||||
mPowEntry = i;
|
||||
PowEntries const& entries (getPowEntries ());
|
||||
mIterations = entries [i].iterations;
|
||||
mTarget.SetHex (entries [i].target);
|
||||
mLastDifficultyChange = now;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
uint64 getDifficulty ()
|
||||
{
|
||||
return ProofOfWork::getDifficulty (mTarget, mIterations);
|
||||
}
|
||||
|
||||
uint256 const& getSecret () const
|
||||
{
|
||||
return mSecret;
|
||||
}
|
||||
|
||||
void setSecret (uint256 const& secret)
|
||||
{
|
||||
mSecret = secret;
|
||||
}
|
||||
|
||||
private:
|
||||
typedef RippleMutex LockType;
|
||||
typedef LockType::ScopedLockType ScopedLockType;
|
||||
LockType mLock;
|
||||
|
||||
uint256 mSecret;
|
||||
int mIterations;
|
||||
uint256 mTarget;
|
||||
time_t mLastDifficultyChange;
|
||||
int mValidTime;
|
||||
int mPowEntry;
|
||||
|
||||
powMap_t mSolvedChallenges;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
ProofOfWorkFactory* ProofOfWorkFactory::New ()
|
||||
{
|
||||
ScopedPointer <ProofOfWorkFactory> object (new ProofOfWorkFactoryImp);
|
||||
return object.release ();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class ProofOfWorkTests : public UnitTest
|
||||
{
|
||||
public:
|
||||
ProofOfWorkTests () : UnitTest ("ProofOfWork", "ripple", runManual)
|
||||
{
|
||||
}
|
||||
|
||||
void runTest ()
|
||||
{
|
||||
using namespace ripple;
|
||||
|
||||
ProofOfWorkFactoryImp gen;
|
||||
ProofOfWork pow = gen.getProof ();
|
||||
|
||||
String s;
|
||||
|
||||
s << "solve difficulty " << String (pow.getDifficulty ());
|
||||
beginTestCase ("solve");
|
||||
|
||||
uint256 solution = pow.solve (16777216);
|
||||
|
||||
expect (! solution.isZero (), "Should be solved");
|
||||
|
||||
expect (pow.checkSolution (solution), "Should be checked");
|
||||
|
||||
// Why is this emitted?
|
||||
//WriteLog (lsDEBUG, ProofOfWork) << "A bad nonce error is expected";
|
||||
|
||||
PowResult r = gen.checkProof (pow.getToken (), uint256 ());
|
||||
|
||||
expect (r == powBADNONCE, "Should show bad nonce for empty solution");
|
||||
|
||||
expect (gen.checkProof (pow.getToken (), solution) == powOK, "Solution should check with issuer");
|
||||
|
||||
//WriteLog (lsDEBUG, ProofOfWork) << "A reused nonce error is expected";
|
||||
|
||||
expect (gen.checkProof (pow.getToken (), solution) == powREUSED, "Reuse solution should be detected");
|
||||
|
||||
#ifdef SOLVE_POWS
|
||||
|
||||
for (int i = 0; i < 12; ++i)
|
||||
{
|
||||
gen.setDifficulty (i);
|
||||
ProofOfWork pow = gen.getProof ();
|
||||
WriteLog (lsINFO, ProofOfWork) << "Level: " << i << ", Estimated difficulty: " << pow.getDifficulty ();
|
||||
uint256 solution = pow.solve (131072);
|
||||
|
||||
if (solution.isZero ())
|
||||
{
|
||||
//WriteLog (lsINFO, ProofOfWork) << "Giving up";
|
||||
}
|
||||
else
|
||||
{
|
||||
//WriteLog (lsINFO, ProofOfWork) << "Solution found";
|
||||
|
||||
if (gen.checkProof (pow.getToken (), solution) != powOK)
|
||||
{
|
||||
//WriteLog (lsFATAL, ProofOfWork) << "Solution fails";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
static ProofOfWorkTests proofOfWorkTests;
|
||||
41
src/ripple_app/misc/ProofOfWorkFactory.h
Normal file
41
src/ripple_app/misc/ProofOfWorkFactory.h
Normal file
@@ -0,0 +1,41 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (c) 2011-2013, OpenCoin, Inc.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef RIPPLE_PROOFOFWORKFACTORY_H_INCLUDED
|
||||
#define RIPPLE_PROOFOFWORKFACTORY_H_INCLUDED
|
||||
|
||||
class ProofOfWorkFactory
|
||||
{
|
||||
public:
|
||||
enum
|
||||
{
|
||||
kMaxDifficulty = 30,
|
||||
};
|
||||
|
||||
static ProofOfWorkFactory* New ();
|
||||
|
||||
virtual ~ProofOfWorkFactory () { }
|
||||
|
||||
virtual ProofOfWork getProof () = 0;
|
||||
|
||||
virtual PowResult checkProof (const std::string& token, uint256 const& solution) = 0;
|
||||
|
||||
virtual uint64 getDifficulty () = 0;
|
||||
|
||||
virtual void setDifficulty (int i) = 0;
|
||||
|
||||
virtual void loadHigh () = 0;
|
||||
|
||||
virtual void loadLow () = 0;
|
||||
|
||||
virtual void sweep () = 0;
|
||||
|
||||
virtual uint256 const& getSecret () const = 0;
|
||||
|
||||
virtual void setSecret (uint256 const& secret) = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
11
src/ripple_app/misc/ripple_AccountItem.cpp
Normal file
11
src/ripple_app/misc/ripple_AccountItem.cpp
Normal file
@@ -0,0 +1,11 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (c) 2011-2013, OpenCoin, Inc.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
AccountItem::AccountItem (SerializedLedgerEntry::ref ledger)
|
||||
: mLedgerEntry (ledger)
|
||||
{
|
||||
|
||||
}
|
||||
74
src/ripple_app/misc/ripple_AccountItem.h
Normal file
74
src/ripple_app/misc/ripple_AccountItem.h
Normal file
@@ -0,0 +1,74 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (c) 2011-2013, OpenCoin, Inc.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef RIPPLE_ACCOUNTITEM_H
|
||||
#define RIPPLE_ACCOUNTITEM_H
|
||||
|
||||
//
|
||||
// Fetch ledger entries from an account's owner dir.
|
||||
//
|
||||
/** Base class representing account items.
|
||||
|
||||
Account items include:
|
||||
|
||||
- Offers
|
||||
- Trust Lines
|
||||
|
||||
NOTE these are deprecated and will go away, to be replaced with
|
||||
simple visitor patterns.
|
||||
*/
|
||||
class AccountItem
|
||||
{
|
||||
public:
|
||||
typedef boost::shared_ptr <AccountItem> pointer;
|
||||
typedef const pointer& ref;
|
||||
|
||||
public:
|
||||
AccountItem ()
|
||||
{ }
|
||||
|
||||
/** Construct from a flat ledger entry.
|
||||
*/
|
||||
explicit AccountItem (SerializedLedgerEntry::ref ledger);
|
||||
|
||||
virtual ~AccountItem ()
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
virtual AccountItem::pointer makeItem (const uint160& accountID, SerializedLedgerEntry::ref ledgerEntry) = 0;
|
||||
|
||||
// VFALCO TODO Make this const and change derived classes
|
||||
virtual LedgerEntryType getType () = 0;
|
||||
|
||||
// VFALCO TODO Document the int parameter
|
||||
virtual Json::Value getJson (int) = 0;
|
||||
|
||||
SerializedLedgerEntry::pointer getSLE ()
|
||||
{
|
||||
return mLedgerEntry;
|
||||
}
|
||||
|
||||
const SerializedLedgerEntry& peekSLE () const
|
||||
{
|
||||
return *mLedgerEntry;
|
||||
}
|
||||
|
||||
SerializedLedgerEntry& peekSLE ()
|
||||
{
|
||||
return *mLedgerEntry;
|
||||
}
|
||||
|
||||
Blob getRaw () const;
|
||||
|
||||
// VFALCO TODO Make this private and use the existing accessors
|
||||
//
|
||||
protected:
|
||||
// VFALCO TODO Research making the object pointed to const
|
||||
SerializedLedgerEntry::pointer mLedgerEntry;
|
||||
};
|
||||
|
||||
#endif
|
||||
68
src/ripple_app/misc/ripple_AccountItems.cpp
Normal file
68
src/ripple_app/misc/ripple_AccountItems.cpp
Normal file
@@ -0,0 +1,68 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (c) 2011-2013, OpenCoin, Inc.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
AccountItems::AccountItems (uint160 const& accountID,
|
||||
Ledger::ref ledger,
|
||||
AccountItem::pointer ofType)
|
||||
{
|
||||
mOfType = ofType;
|
||||
|
||||
fillItems (accountID, ledger);
|
||||
}
|
||||
|
||||
void AccountItems::fillItems (const uint160& accountID, Ledger::ref ledger)
|
||||
{
|
||||
uint256 const rootIndex = Ledger::getOwnerDirIndex (accountID);
|
||||
uint256 currentIndex = rootIndex;
|
||||
|
||||
// VFALCO TODO Rewrite all infinite loops to have clear terminating
|
||||
// conditions defined in one location.
|
||||
//
|
||||
while (1)
|
||||
{
|
||||
SLE::pointer ownerDir = ledger->getDirNode (currentIndex);
|
||||
|
||||
// VFALCO TODO Rewrite to not return from the middle of the function
|
||||
if (!ownerDir)
|
||||
return;
|
||||
|
||||
BOOST_FOREACH (uint256 const & uNode, ownerDir->getFieldV256 (sfIndexes).peekValue ())
|
||||
{
|
||||
// VFALCO TODO rename getSLEi() to something legible.
|
||||
SLE::pointer sleCur = ledger->getSLEi (uNode);
|
||||
|
||||
AccountItem::pointer item = mOfType->makeItem (accountID, sleCur);
|
||||
|
||||
// VFALCO NOTE Under what conditions would makeItem() return nullptr?
|
||||
if (item)
|
||||
{
|
||||
mItems.push_back (item);
|
||||
}
|
||||
}
|
||||
|
||||
uint64 uNodeNext = ownerDir->getFieldU64 (sfIndexNext);
|
||||
|
||||
// VFALCO TODO Rewrite to not return from the middle of the function
|
||||
if (!uNodeNext)
|
||||
return;
|
||||
|
||||
currentIndex = Ledger::getDirNodeIndex (rootIndex, uNodeNext);
|
||||
}
|
||||
}
|
||||
|
||||
Json::Value AccountItems::getJson (int v)
|
||||
{
|
||||
Json::Value ret (Json::arrayValue);
|
||||
|
||||
BOOST_FOREACH (AccountItem::ref ai, mItems)
|
||||
{
|
||||
ret.append (ai->getJson (v));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// vim:ts=4
|
||||
45
src/ripple_app/misc/ripple_AccountItems.h
Normal file
45
src/ripple_app/misc/ripple_AccountItems.h
Normal file
@@ -0,0 +1,45 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (c) 2011-2013, OpenCoin, Inc.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef RIPPLE_ACCOUNTITEMS_H
|
||||
#define RIPPLE_ACCOUNTITEMS_H
|
||||
|
||||
/** A set of AccountItem objects.
|
||||
*/
|
||||
class AccountItems : LeakChecked <AccountItems>
|
||||
{
|
||||
public:
|
||||
typedef boost::shared_ptr <AccountItems> pointer;
|
||||
|
||||
typedef std::vector <AccountItem::pointer> Container;
|
||||
|
||||
// VFALCO TODO Create a typedef uint160 AccountID and replace
|
||||
AccountItems (uint160 const& accountID,
|
||||
Ledger::ref ledger,
|
||||
AccountItem::pointer ofType);
|
||||
|
||||
// VFALCO TODO rename to getContainer and make this change in every interface
|
||||
// that exposes the caller to the type of container.
|
||||
//
|
||||
Container& getItems ()
|
||||
{
|
||||
return mItems;
|
||||
}
|
||||
|
||||
// VFALCO TODO What is the int for?
|
||||
Json::Value getJson (int);
|
||||
|
||||
private:
|
||||
void fillItems (const uint160& accountID, Ledger::ref ledger);
|
||||
|
||||
private:
|
||||
// VFALCO TODO This looks like its used as an exemplar, rename appropriately
|
||||
AccountItem::pointer mOfType;
|
||||
|
||||
Container mItems;
|
||||
};
|
||||
|
||||
#endif
|
||||
69
src/ripple_app/misc/ripple_AccountState.cpp
Normal file
69
src/ripple_app/misc/ripple_AccountState.cpp
Normal file
@@ -0,0 +1,69 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (c) 2011-2013, OpenCoin, Inc.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
AccountState::AccountState (RippleAddress const& naAccountID)
|
||||
: mAccountID (naAccountID)
|
||||
, mValid (false)
|
||||
{
|
||||
if (naAccountID.isValid ())
|
||||
{
|
||||
mValid = true;
|
||||
|
||||
mLedgerEntry = boost::make_shared <SerializedLedgerEntry> (
|
||||
ltACCOUNT_ROOT, Ledger::getAccountRootIndex (naAccountID));
|
||||
|
||||
mLedgerEntry->setFieldAccount (sfAccount, naAccountID.getAccountID ());
|
||||
}
|
||||
}
|
||||
|
||||
AccountState::AccountState (SLE::ref ledgerEntry, const RippleAddress& naAccountID) :
|
||||
mAccountID (naAccountID), mLedgerEntry (ledgerEntry), mValid (false)
|
||||
{
|
||||
if (!mLedgerEntry)
|
||||
return;
|
||||
|
||||
if (mLedgerEntry->getType () != ltACCOUNT_ROOT)
|
||||
return;
|
||||
|
||||
mValid = true;
|
||||
}
|
||||
|
||||
// VFALCO TODO Make this a generic utility function of some container class
|
||||
//
|
||||
std::string AccountState::createGravatarUrl (uint128 uEmailHash)
|
||||
{
|
||||
Blob vucMD5 (uEmailHash.begin (), uEmailHash.end ());
|
||||
std::string strMD5Lower = strHex (vucMD5);
|
||||
boost::to_lower (strMD5Lower);
|
||||
|
||||
// VFALCO TODO Give a name and move this constant to a more visible location.
|
||||
// Also shouldn't this be https?
|
||||
return str (boost::format ("http://www.gravatar.com/avatar/%s") % strMD5Lower);
|
||||
}
|
||||
|
||||
void AccountState::addJson (Json::Value& val)
|
||||
{
|
||||
val = mLedgerEntry->getJson (0);
|
||||
|
||||
if (mValid)
|
||||
{
|
||||
if (mLedgerEntry->isFieldPresent (sfEmailHash))
|
||||
val["urlgravatar"] = createGravatarUrl (mLedgerEntry->getFieldH128 (sfEmailHash));
|
||||
}
|
||||
else
|
||||
{
|
||||
val["Invalid"] = true;
|
||||
}
|
||||
}
|
||||
|
||||
void AccountState::dump ()
|
||||
{
|
||||
Json::Value j (Json::objectValue);
|
||||
addJson (j);
|
||||
Log (lsINFO) << j;
|
||||
}
|
||||
|
||||
// vim:ts=4
|
||||
77
src/ripple_app/misc/ripple_AccountState.h
Normal file
77
src/ripple_app/misc/ripple_AccountState.h
Normal file
@@ -0,0 +1,77 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (c) 2011-2013, OpenCoin, Inc.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef RIPPLE_ACCOUNTSTATE_H
|
||||
#define RIPPLE_ACCOUNTSTATE_H
|
||||
|
||||
//
|
||||
// Provide abstract access to an account's state, such that access to the serialized format is hidden.
|
||||
//
|
||||
|
||||
class AccountState : LeakChecked <AccountState>
|
||||
{
|
||||
public:
|
||||
typedef boost::shared_ptr<AccountState> pointer;
|
||||
|
||||
public:
|
||||
// For new accounts
|
||||
explicit AccountState (RippleAddress const& naAccountID);
|
||||
|
||||
// For accounts in a ledger
|
||||
AccountState (SLE::ref ledgerEntry, RippleAddress const& naAccountI);
|
||||
|
||||
bool haveAuthorizedKey ()
|
||||
{
|
||||
return mLedgerEntry->isFieldPresent (sfRegularKey);
|
||||
}
|
||||
|
||||
RippleAddress getAuthorizedKey ()
|
||||
{
|
||||
return mLedgerEntry->getFieldAccount (sfRegularKey);
|
||||
}
|
||||
|
||||
STAmount getBalance () const
|
||||
{
|
||||
return mLedgerEntry->getFieldAmount (sfBalance);
|
||||
}
|
||||
|
||||
uint32 getSeq () const
|
||||
{
|
||||
return mLedgerEntry->getFieldU32 (sfSequence);
|
||||
}
|
||||
|
||||
SerializedLedgerEntry::pointer getSLE ()
|
||||
{
|
||||
return mLedgerEntry;
|
||||
}
|
||||
|
||||
SerializedLedgerEntry const& peekSLE () const
|
||||
{
|
||||
return *mLedgerEntry;
|
||||
}
|
||||
|
||||
SerializedLedgerEntry& peekSLE ()
|
||||
{
|
||||
return *mLedgerEntry;
|
||||
}
|
||||
|
||||
Blob getRaw () const;
|
||||
|
||||
void addJson (Json::Value& value);
|
||||
|
||||
void dump ();
|
||||
|
||||
static std::string createGravatarUrl (uint128 uEmailHash);
|
||||
|
||||
private:
|
||||
RippleAddress const mAccountID;
|
||||
RippleAddress mAuthorizedKey;
|
||||
SerializedLedgerEntry::pointer mLedgerEntry;
|
||||
|
||||
bool mValid;
|
||||
};
|
||||
|
||||
#endif
|
||||
78
src/ripple_app/misc/ripple_CanonicalTXSet.cpp
Normal file
78
src/ripple_app/misc/ripple_CanonicalTXSet.cpp
Normal file
@@ -0,0 +1,78 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (c) 2011-2013, OpenCoin, Inc.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
bool CanonicalTXSet::Key::operator< (Key const& rhs) const
|
||||
{
|
||||
if (mAccount < rhs.mAccount) return true;
|
||||
|
||||
if (mAccount > rhs.mAccount) return false;
|
||||
|
||||
if (mSeq < rhs.mSeq) return true;
|
||||
|
||||
if (mSeq > rhs.mSeq) return false;
|
||||
|
||||
return mTXid < rhs.mTXid;
|
||||
}
|
||||
|
||||
bool CanonicalTXSet::Key::operator> (Key const& rhs) const
|
||||
{
|
||||
if (mAccount > rhs.mAccount) return true;
|
||||
|
||||
if (mAccount < rhs.mAccount) return false;
|
||||
|
||||
if (mSeq > rhs.mSeq) return true;
|
||||
|
||||
if (mSeq < rhs.mSeq) return false;
|
||||
|
||||
return mTXid > rhs.mTXid;
|
||||
}
|
||||
|
||||
bool CanonicalTXSet::Key::operator<= (Key const& rhs) const
|
||||
{
|
||||
if (mAccount < rhs.mAccount) return true;
|
||||
|
||||
if (mAccount > rhs.mAccount) return false;
|
||||
|
||||
if (mSeq < rhs.mSeq) return true;
|
||||
|
||||
if (mSeq > rhs.mSeq) return false;
|
||||
|
||||
return mTXid <= rhs.mTXid;
|
||||
}
|
||||
|
||||
bool CanonicalTXSet::Key::operator>= (Key const& rhs)const
|
||||
{
|
||||
if (mAccount > rhs.mAccount) return true;
|
||||
|
||||
if (mAccount < rhs.mAccount) return false;
|
||||
|
||||
if (mSeq > rhs.mSeq) return true;
|
||||
|
||||
if (mSeq < rhs.mSeq) return false;
|
||||
|
||||
return mTXid >= rhs.mTXid;
|
||||
}
|
||||
|
||||
void CanonicalTXSet::push_back (SerializedTransaction::ref txn)
|
||||
{
|
||||
uint256 effectiveAccount = mSetHash;
|
||||
|
||||
effectiveAccount ^= txn->getSourceAccount ().getAccountID ().to256 ();
|
||||
|
||||
mMap.insert (std::make_pair (
|
||||
Key (effectiveAccount, txn->getSequence (), txn->getTransactionID ()),
|
||||
txn));
|
||||
}
|
||||
|
||||
CanonicalTXSet::iterator CanonicalTXSet::erase (iterator const& it)
|
||||
{
|
||||
iterator tmp = it;
|
||||
++tmp;
|
||||
mMap.erase (it);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
|
||||
109
src/ripple_app/misc/ripple_CanonicalTXSet.h
Normal file
109
src/ripple_app/misc/ripple_CanonicalTXSet.h
Normal file
@@ -0,0 +1,109 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (c) 2011-2013, OpenCoin, Inc.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef RIPPLE_CANONICALTXSET_H
|
||||
#define RIPPLE_CANONICALTXSET_H
|
||||
|
||||
/** Holds transactions which were deferred to the next pass of consensus.
|
||||
|
||||
"Canonical" refers to the order in which transactions are applied.
|
||||
|
||||
- Puts transactions from the same account in sequence order
|
||||
|
||||
*/
|
||||
// VFALCO TODO rename to SortedTxSet
|
||||
class CanonicalTXSet : LeakChecked <CanonicalTXSet>
|
||||
{
|
||||
public:
|
||||
class Key
|
||||
{
|
||||
public:
|
||||
Key (uint256 const& account, uint32 seq, uint256 const& id)
|
||||
: mAccount (account)
|
||||
, mTXid (id)
|
||||
, mSeq (seq)
|
||||
{
|
||||
}
|
||||
|
||||
bool operator< (Key const& rhs) const;
|
||||
bool operator> (Key const& rhs) const;
|
||||
bool operator<= (Key const& rhs) const;
|
||||
bool operator>= (Key const& rhs) const;
|
||||
|
||||
bool operator== (Key const& rhs) const
|
||||
{
|
||||
return mTXid == rhs.mTXid;
|
||||
}
|
||||
bool operator!= (Key const& rhs) const
|
||||
{
|
||||
return mTXid != rhs.mTXid;
|
||||
}
|
||||
|
||||
uint256 const& getTXID () const
|
||||
{
|
||||
return mTXid;
|
||||
}
|
||||
|
||||
private:
|
||||
uint256 mAccount;
|
||||
uint256 mTXid;
|
||||
uint32 mSeq;
|
||||
};
|
||||
|
||||
typedef std::map <Key, SerializedTransaction::pointer>::iterator iterator;
|
||||
typedef std::map <Key, SerializedTransaction::pointer>::const_iterator const_iterator;
|
||||
|
||||
public:
|
||||
explicit CanonicalTXSet (LedgerHash const& lastClosedLedgerHash)
|
||||
: mSetHash (lastClosedLedgerHash)
|
||||
{
|
||||
}
|
||||
|
||||
void push_back (SerializedTransaction::ref txn);
|
||||
|
||||
// VFALCO TODO remove this function
|
||||
void reset (LedgerHash const& newLastClosedLedgerHash)
|
||||
{
|
||||
mSetHash = newLastClosedLedgerHash;
|
||||
|
||||
mMap.clear ();
|
||||
}
|
||||
|
||||
iterator erase (iterator const& it);
|
||||
|
||||
iterator begin ()
|
||||
{
|
||||
return mMap.begin ();
|
||||
}
|
||||
iterator end ()
|
||||
{
|
||||
return mMap.end ();
|
||||
}
|
||||
const_iterator begin () const
|
||||
{
|
||||
return mMap.begin ();
|
||||
}
|
||||
const_iterator end () const
|
||||
{
|
||||
return mMap.end ();
|
||||
}
|
||||
size_t size () const
|
||||
{
|
||||
return mMap.size ();
|
||||
}
|
||||
bool empty () const
|
||||
{
|
||||
return mMap.empty ();
|
||||
}
|
||||
|
||||
private:
|
||||
// Used to salt the accounts so people can't mine for low account numbers
|
||||
uint256 mSetHash;
|
||||
|
||||
std::map <Key, SerializedTransaction::pointer> mMap;
|
||||
};
|
||||
|
||||
#endif
|
||||
544
src/ripple_app/misc/ripple_Features.cpp
Normal file
544
src/ripple_app/misc/ripple_Features.cpp
Normal file
@@ -0,0 +1,544 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (c) 2011-2013, OpenCoin, Inc.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
class Features;
|
||||
|
||||
SETUP_LOG (Features)
|
||||
|
||||
FeatureState* testFeature = NULL;
|
||||
|
||||
// VFALCO TODO Rename this to Features
|
||||
class Features : public IFeatures
|
||||
{
|
||||
protected:
|
||||
|
||||
typedef boost::unordered_map<uint256, FeatureState> featureMap_t;
|
||||
typedef std::pair<const uint256, FeatureState> featureIt_t;
|
||||
typedef boost::unordered_set<uint256> featureList_t;
|
||||
|
||||
typedef RippleMutex LockType;
|
||||
typedef LockType::ScopedLockType ScopedLockType;
|
||||
LockType mLock;
|
||||
|
||||
featureMap_t mFeatureMap;
|
||||
int mMajorityTime; // Seconds a feature must hold a majority
|
||||
int mMajorityFraction; // 256 = 100%
|
||||
uint32 mFirstReport; // close time of first majority report
|
||||
uint32 mLastReport; // close time of most recent majority report
|
||||
|
||||
FeatureState* getCreateFeature (uint256 const& feature, bool create);
|
||||
bool shouldEnable (uint32 closeTime, const FeatureState& fs);
|
||||
void setJson (Json::Value& v, const FeatureState&);
|
||||
|
||||
public:
|
||||
|
||||
Features (uint32 majorityTime, int majorityFraction)
|
||||
: mLock (this, "Features", __FILE__, __LINE__)
|
||||
, mMajorityTime (majorityTime), mMajorityFraction (majorityFraction), mFirstReport (0), mLastReport (0)
|
||||
{
|
||||
}
|
||||
|
||||
void addInitialFeatures ();
|
||||
|
||||
FeatureState* addKnownFeature (const char* featureID, const char* friendlyName, bool veto);
|
||||
uint256 getFeature (const std::string& name);
|
||||
|
||||
bool vetoFeature (uint256 const& feature);
|
||||
bool unVetoFeature (uint256 const& feature);
|
||||
|
||||
bool enableFeature (uint256 const& feature);
|
||||
bool disableFeature (uint256 const& feature);
|
||||
|
||||
bool isFeatureEnabled (uint256 const& feature);
|
||||
bool isFeatureSupported (uint256 const& feature);
|
||||
|
||||
void setEnabledFeatures (const std::vector<uint256>& features);
|
||||
void setSupportedFeatures (const std::vector<uint256>& features);
|
||||
|
||||
featureList_t getVetoedFeatures ();
|
||||
featureList_t getEnabledFeatures ();
|
||||
featureList_t getFeaturesToEnable (uint32 closeTime); // gets features we would vote to enable
|
||||
featureList_t getDesiredFeatures (); // features we support, do not veto, are not enabled
|
||||
|
||||
void reportValidations (const FeatureSet&);
|
||||
|
||||
Json::Value getJson (int);
|
||||
Json::Value getJson (uint256 const& );
|
||||
|
||||
void doValidation (Ledger::ref lastClosedLedger, STObject& baseValidation);
|
||||
void doVoting (Ledger::ref lastClosedLedger, SHAMap::ref initialPosition);
|
||||
};
|
||||
|
||||
void Features::addInitialFeatures ()
|
||||
{
|
||||
// For each feature this version supports, construct the FeatureState object by calling
|
||||
// getCreateFeature. Set any vetoes or defaults. A pointer to the FeatureState can be stashed
|
||||
|
||||
testFeature = addKnownFeature ("1234", "testFeature", false);
|
||||
}
|
||||
|
||||
FeatureState* Features::getCreateFeature (uint256 const& featureHash, bool create)
|
||||
{
|
||||
// call with the mutex held
|
||||
featureMap_t::iterator it = mFeatureMap.find (featureHash);
|
||||
|
||||
if (it == mFeatureMap.end ())
|
||||
{
|
||||
if (!create)
|
||||
return NULL;
|
||||
|
||||
FeatureState* feature = & (mFeatureMap[featureHash]);
|
||||
|
||||
{
|
||||
std::string query = "SELECT FirstMajority,LastMajority FROM Features WHERE hash='";
|
||||
query.append (featureHash.GetHex ());
|
||||
query.append ("';");
|
||||
|
||||
DeprecatedScopedLock sl (getApp().getWalletDB ()->getDBLock ());
|
||||
Database* db = getApp().getWalletDB ()->getDB ();
|
||||
|
||||
if (db->executeSQL (query) && db->startIterRows ())
|
||||
{
|
||||
feature->mFirstMajority = db->getBigInt ("FirstMajority");
|
||||
feature->mLastMajority = db->getBigInt ("LastMajority");
|
||||
db->endIterRows ();
|
||||
}
|
||||
}
|
||||
|
||||
return feature;
|
||||
}
|
||||
|
||||
return & (it->second);
|
||||
}
|
||||
|
||||
uint256 Features::getFeature (const std::string& name)
|
||||
{
|
||||
if (!name.empty ())
|
||||
{
|
||||
BOOST_FOREACH (featureMap_t::value_type & it, mFeatureMap)
|
||||
{
|
||||
if (name == it.second.mFriendlyName)
|
||||
return it.first;
|
||||
}
|
||||
}
|
||||
|
||||
return uint256 ();
|
||||
}
|
||||
|
||||
FeatureState* Features::addKnownFeature (const char* featureID, const char* friendlyName, bool veto)
|
||||
{
|
||||
uint256 hash;
|
||||
hash.SetHex (featureID);
|
||||
|
||||
if (hash.isZero ())
|
||||
{
|
||||
assert (false);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
FeatureState* f = getCreateFeature (hash, true);
|
||||
|
||||
if (friendlyName != NULL)
|
||||
f->setFriendlyName (friendlyName);
|
||||
|
||||
f->mVetoed = veto;
|
||||
f->mSupported = true;
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
bool Features::vetoFeature (uint256 const& feature)
|
||||
{
|
||||
ScopedLockType sl (mLock, __FILE__, __LINE__);
|
||||
FeatureState* s = getCreateFeature (feature, true);
|
||||
|
||||
if (s->mVetoed)
|
||||
return false;
|
||||
|
||||
s->mVetoed = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Features::unVetoFeature (uint256 const& feature)
|
||||
{
|
||||
ScopedLockType sl (mLock, __FILE__, __LINE__);
|
||||
FeatureState* s = getCreateFeature (feature, false);
|
||||
|
||||
if (!s || !s->mVetoed)
|
||||
return false;
|
||||
|
||||
s->mVetoed = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Features::enableFeature (uint256 const& feature)
|
||||
{
|
||||
ScopedLockType sl (mLock, __FILE__, __LINE__);
|
||||
FeatureState* s = getCreateFeature (feature, true);
|
||||
|
||||
if (s->mEnabled)
|
||||
return false;
|
||||
|
||||
s->mEnabled = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Features::disableFeature (uint256 const& feature)
|
||||
{
|
||||
ScopedLockType sl (mLock, __FILE__, __LINE__);
|
||||
FeatureState* s = getCreateFeature (feature, false);
|
||||
|
||||
if (!s || !s->mEnabled)
|
||||
return false;
|
||||
|
||||
s->mEnabled = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Features::isFeatureEnabled (uint256 const& feature)
|
||||
{
|
||||
ScopedLockType sl (mLock, __FILE__, __LINE__);
|
||||
FeatureState* s = getCreateFeature (feature, false);
|
||||
return s && s->mEnabled;
|
||||
}
|
||||
|
||||
bool Features::isFeatureSupported (uint256 const& feature)
|
||||
{
|
||||
ScopedLockType sl (mLock, __FILE__, __LINE__);
|
||||
FeatureState* s = getCreateFeature (feature, false);
|
||||
return s && s->mSupported;
|
||||
}
|
||||
|
||||
Features::featureList_t Features::getVetoedFeatures ()
|
||||
{
|
||||
featureList_t ret;
|
||||
ScopedLockType sl (mLock, __FILE__, __LINE__);
|
||||
BOOST_FOREACH (const featureIt_t & it, mFeatureMap)
|
||||
{
|
||||
if (it.second.mVetoed)
|
||||
ret.insert (it.first);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
Features::featureList_t Features::getEnabledFeatures ()
|
||||
{
|
||||
featureList_t ret;
|
||||
ScopedLockType sl (mLock, __FILE__, __LINE__);
|
||||
BOOST_FOREACH (const featureIt_t & it, mFeatureMap)
|
||||
{
|
||||
if (it.second.mEnabled)
|
||||
ret.insert (it.first);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool Features::shouldEnable (uint32 closeTime, const FeatureState& fs)
|
||||
{
|
||||
if (fs.mVetoed || fs.mEnabled || !fs.mSupported || (fs.mLastMajority != mLastReport))
|
||||
return false;
|
||||
|
||||
if (fs.mFirstMajority == mFirstReport)
|
||||
{
|
||||
// had a majority when we first started the server, relaxed check
|
||||
// WRITEME
|
||||
}
|
||||
|
||||
// didn't have a majority when we first started the server, normal check
|
||||
return (fs.mLastMajority - fs.mFirstMajority) > mMajorityTime;
|
||||
|
||||
}
|
||||
|
||||
Features::featureList_t Features::getFeaturesToEnable (uint32 closeTime)
|
||||
{
|
||||
featureList_t ret;
|
||||
ScopedLockType sl (mLock, __FILE__, __LINE__);
|
||||
|
||||
if (mLastReport != 0)
|
||||
{
|
||||
BOOST_FOREACH (const featureIt_t & it, mFeatureMap)
|
||||
{
|
||||
if (shouldEnable (closeTime, it.second))
|
||||
ret.insert (it.first);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
Features::featureList_t Features::getDesiredFeatures ()
|
||||
{
|
||||
featureList_t ret;
|
||||
ScopedLockType sl (mLock, __FILE__, __LINE__);
|
||||
BOOST_FOREACH (const featureIt_t & it, mFeatureMap)
|
||||
{
|
||||
if (it.second.mSupported && !it.second.mEnabled && !it.second.mVetoed)
|
||||
ret.insert (it.first);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void Features::reportValidations (const FeatureSet& set)
|
||||
{
|
||||
if (set.mTrustedValidations == 0)
|
||||
return;
|
||||
|
||||
int threshold = (set.mTrustedValidations * mMajorityFraction) / 256;
|
||||
|
||||
typedef std::map<uint256, int>::value_type u256_int_pair;
|
||||
|
||||
ScopedLockType sl (mLock, __FILE__, __LINE__);
|
||||
|
||||
if (mFirstReport == 0)
|
||||
mFirstReport = set.mCloseTime;
|
||||
|
||||
std::vector<uint256> changedFeatures;
|
||||
changedFeatures.resize (set.mVotes.size ());
|
||||
|
||||
BOOST_FOREACH (const u256_int_pair & it, set.mVotes)
|
||||
{
|
||||
FeatureState& state = mFeatureMap[it.first];
|
||||
WriteLog (lsDEBUG, Features) << "Feature " << it.first.GetHex () << " has " << it.second << " votes, needs " << threshold;
|
||||
|
||||
if (it.second >= threshold)
|
||||
{
|
||||
// we have a majority
|
||||
state.mLastMajority = set.mCloseTime;
|
||||
|
||||
if (state.mFirstMajority == 0)
|
||||
{
|
||||
WriteLog (lsWARNING, Features) << "Feature " << it.first << " attains a majority vote";
|
||||
state.mFirstMajority = set.mCloseTime;
|
||||
changedFeatures.push_back (it.first);
|
||||
}
|
||||
}
|
||||
else // we have no majority
|
||||
{
|
||||
if (state.mFirstMajority != 0)
|
||||
{
|
||||
WriteLog (lsWARNING, Features) << "Feature " << it.first << " loses majority vote";
|
||||
state.mFirstMajority = 0;
|
||||
state.mLastMajority = 0;
|
||||
changedFeatures.push_back (it.first);
|
||||
}
|
||||
}
|
||||
}
|
||||
mLastReport = set.mCloseTime;
|
||||
|
||||
if (!changedFeatures.empty ())
|
||||
{
|
||||
DeprecatedScopedLock sl (getApp().getWalletDB ()->getDBLock ());
|
||||
Database* db = getApp().getWalletDB ()->getDB ();
|
||||
|
||||
db->executeSQL ("BEGIN TRANSACTION;");
|
||||
BOOST_FOREACH (uint256 const & hash, changedFeatures)
|
||||
{
|
||||
FeatureState& fState = mFeatureMap[hash];
|
||||
db->executeSQL (boost::str (boost::format (
|
||||
"UPDATE Features SET FirstMajority = %d WHERE Hash = '%s';"
|
||||
) % fState.mFirstMajority % hash.GetHex ()));
|
||||
db->executeSQL (boost::str (boost::format (
|
||||
"UPDATE Features SET LastMajority = %d WHERE Hash = '%s';"
|
||||
) % fState.mLastMajority % hash.GetHex ()));
|
||||
}
|
||||
db->executeSQL ("END TRANSACTION;");
|
||||
changedFeatures.clear ();
|
||||
}
|
||||
}
|
||||
|
||||
void Features::setEnabledFeatures (const std::vector<uint256>& features)
|
||||
{
|
||||
ScopedLockType sl (mLock, __FILE__, __LINE__);
|
||||
BOOST_FOREACH (featureIt_t & it, mFeatureMap)
|
||||
{
|
||||
it.second.mEnabled = false;
|
||||
}
|
||||
BOOST_FOREACH (uint256 const & it, features)
|
||||
{
|
||||
mFeatureMap[it].mEnabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
void Features::setSupportedFeatures (const std::vector<uint256>& features)
|
||||
{
|
||||
ScopedLockType sl (mLock, __FILE__, __LINE__);
|
||||
BOOST_FOREACH (featureIt_t & it, mFeatureMap)
|
||||
{
|
||||
it.second.mSupported = false;
|
||||
}
|
||||
BOOST_FOREACH (uint256 const & it, features)
|
||||
{
|
||||
mFeatureMap[it].mSupported = true;
|
||||
}
|
||||
}
|
||||
|
||||
void Features::doValidation (Ledger::ref lastClosedLedger, STObject& baseValidation)
|
||||
{
|
||||
featureList_t lFeatures = getDesiredFeatures ();
|
||||
|
||||
if (lFeatures.empty ())
|
||||
return;
|
||||
|
||||
STVector256 vFeatures (sfFeatures);
|
||||
BOOST_FOREACH (uint256 const & uFeature, lFeatures)
|
||||
{
|
||||
vFeatures.addValue (uFeature);
|
||||
}
|
||||
vFeatures.sort ();
|
||||
baseValidation.setFieldV256 (sfFeatures, vFeatures);
|
||||
}
|
||||
|
||||
void Features::doVoting (Ledger::ref lastClosedLedger, SHAMap::ref initialPosition)
|
||||
{
|
||||
featureList_t lFeatures = getFeaturesToEnable (lastClosedLedger->getCloseTimeNC ());
|
||||
|
||||
if (lFeatures.empty ())
|
||||
return;
|
||||
|
||||
BOOST_FOREACH (uint256 const & uFeature, lFeatures)
|
||||
{
|
||||
WriteLog (lsWARNING, Features) << "Voting for feature: " << uFeature;
|
||||
SerializedTransaction trans (ttFEATURE);
|
||||
trans.setFieldAccount (sfAccount, uint160 ());
|
||||
trans.setFieldH256 (sfFeature, uFeature);
|
||||
uint256 txID = trans.getTransactionID ();
|
||||
WriteLog (lsWARNING, Features) << "Vote ID: " << txID;
|
||||
|
||||
Serializer s;
|
||||
trans.add (s, true);
|
||||
|
||||
SHAMapItem::pointer tItem = boost::make_shared<SHAMapItem> (txID, s.peekData ());
|
||||
|
||||
if (!initialPosition->addGiveItem (tItem, true, false))
|
||||
{
|
||||
WriteLog (lsWARNING, Features) << "Ledger already had feature transaction";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Json::Value Features::getJson (int)
|
||||
{
|
||||
Json::Value ret (Json::objectValue);
|
||||
{
|
||||
ScopedLockType sl (mLock, __FILE__, __LINE__);
|
||||
BOOST_FOREACH (const featureIt_t & it, mFeatureMap)
|
||||
{
|
||||
setJson (ret[it.first.GetHex ()] = Json::objectValue, it.second);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void Features::setJson (Json::Value& v, const FeatureState& fs)
|
||||
{
|
||||
if (!fs.mFriendlyName.empty ())
|
||||
v["name"] = fs.mFriendlyName;
|
||||
|
||||
v["supported"] = fs.mSupported;
|
||||
v["vetoed"] = fs.mVetoed;
|
||||
|
||||
if (fs.mEnabled)
|
||||
v["enabled"] = true;
|
||||
else
|
||||
{
|
||||
v["enabled"] = false;
|
||||
|
||||
if (mLastReport != 0)
|
||||
{
|
||||
if (fs.mLastMajority == 0)
|
||||
{
|
||||
v["majority"] = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (fs.mFirstMajority != 0)
|
||||
{
|
||||
if (fs.mFirstMajority == mFirstReport)
|
||||
v["majority_start"] = "start";
|
||||
else
|
||||
v["majority_start"] = fs.mFirstMajority;
|
||||
}
|
||||
|
||||
if (fs.mLastMajority != 0)
|
||||
{
|
||||
if (fs.mLastMajority == mLastReport)
|
||||
v["majority_until"] = "now";
|
||||
else
|
||||
v["majority_until"] = fs.mLastMajority;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (fs.mVetoed)
|
||||
v["veto"] = true;
|
||||
}
|
||||
|
||||
Json::Value Features::getJson (uint256 const& feature)
|
||||
{
|
||||
Json::Value ret = Json::objectValue;
|
||||
ScopedLockType sl (mLock, __FILE__, __LINE__);
|
||||
setJson (ret[feature.GetHex ()] = Json::objectValue, *getCreateFeature (feature, true));
|
||||
return ret;
|
||||
}
|
||||
|
||||
template<typename INT> class VotableInteger
|
||||
{
|
||||
protected:
|
||||
INT mCurrent; // The current setting
|
||||
INT mTarget; // The setting we want
|
||||
std::map<INT, int> mVoteMap;
|
||||
|
||||
public:
|
||||
VotableInteger (INT current, INT target) : mCurrent (current), mTarget (target)
|
||||
{
|
||||
++mVoteMap[mTarget]; // Add our vote
|
||||
}
|
||||
|
||||
bool mayVote ()
|
||||
{
|
||||
return mCurrent != mTarget; // If we love the current setting, we will not vote
|
||||
}
|
||||
|
||||
void addVote (INT vote)
|
||||
{
|
||||
++mVoteMap[vote];
|
||||
}
|
||||
|
||||
void noVote ()
|
||||
{
|
||||
addVote (mCurrent);
|
||||
}
|
||||
|
||||
INT getVotes ()
|
||||
{
|
||||
INT ourVote = mCurrent;
|
||||
int weight = 0;
|
||||
|
||||
typedef typename std::map<INT, int>::value_type mapVType;
|
||||
BOOST_FOREACH (const mapVType & value, mVoteMap)
|
||||
{
|
||||
// Take most voted value between current and target, inclusive
|
||||
// FIXME: Should take best value that can get a significant majority
|
||||
if ((value.first <= std::max (mTarget, mCurrent)) &&
|
||||
(value.first >= std::min (mTarget, mCurrent)) &&
|
||||
(value.second > weight))
|
||||
{
|
||||
ourVote = value.first;
|
||||
weight = value.second;
|
||||
}
|
||||
}
|
||||
|
||||
return ourVote;
|
||||
}
|
||||
};
|
||||
|
||||
IFeatures* IFeatures::New (uint32 majorityTime, int majorityFraction)
|
||||
{
|
||||
return new Features (majorityTime, majorityFraction);
|
||||
}
|
||||
|
||||
// vim:ts=4
|
||||
194
src/ripple_app/misc/ripple_FeeVote.cpp
Normal file
194
src/ripple_app/misc/ripple_FeeVote.cpp
Normal file
@@ -0,0 +1,194 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (c) 2011-2013, OpenCoin, Inc.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
class Features;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class FeeVote : public IFeeVote
|
||||
{
|
||||
private:
|
||||
// VFALCO TODO rename template parameter (wtf, looks like a macro)
|
||||
template <typename INT>
|
||||
class VotableInteger
|
||||
{
|
||||
public:
|
||||
VotableInteger (INT current, INT target) : mCurrent (current), mTarget (target)
|
||||
{
|
||||
++mVoteMap[mTarget]; // Add our vote
|
||||
}
|
||||
|
||||
bool mayVote ()
|
||||
{
|
||||
return mCurrent != mTarget; // If we love the current setting, we will not vote
|
||||
}
|
||||
|
||||
void addVote (INT vote)
|
||||
{
|
||||
++mVoteMap[vote];
|
||||
}
|
||||
|
||||
void noVote ()
|
||||
{
|
||||
addVote (mCurrent);
|
||||
}
|
||||
|
||||
INT getVotes ()
|
||||
{
|
||||
INT ourVote = mCurrent;
|
||||
int weight = 0;
|
||||
|
||||
typedef typename std::map<INT, int>::value_type mapVType;
|
||||
BOOST_FOREACH (const mapVType & value, mVoteMap)
|
||||
{
|
||||
// Take most voted value between current and target, inclusive
|
||||
if ((value.first <= std::max (mTarget, mCurrent)) &&
|
||||
(value.first >= std::min (mTarget, mCurrent)) &&
|
||||
(value.second > weight))
|
||||
{
|
||||
ourVote = value.first;
|
||||
weight = value.second;
|
||||
}
|
||||
}
|
||||
|
||||
return ourVote;
|
||||
}
|
||||
|
||||
private:
|
||||
INT mCurrent; // The current setting
|
||||
INT mTarget; // The setting we want
|
||||
std::map<INT, int> mVoteMap;
|
||||
};
|
||||
public:
|
||||
FeeVote (uint64 targetBaseFee, uint32 targetReserveBase, uint32 targetReserveIncrement)
|
||||
: mTargetBaseFee (targetBaseFee)
|
||||
, mTargetReserveBase (targetReserveBase)
|
||||
, mTargetReserveIncrement (targetReserveIncrement)
|
||||
{
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
void doValidation (Ledger::ref lastClosedLedger, STObject& baseValidation)
|
||||
{
|
||||
if (lastClosedLedger->getBaseFee () != mTargetBaseFee)
|
||||
{
|
||||
WriteLog (lsINFO, Features) << "Voting for base fee of " << mTargetBaseFee;
|
||||
baseValidation.setFieldU64 (sfBaseFee, mTargetBaseFee);
|
||||
}
|
||||
|
||||
if (lastClosedLedger->getReserve (0) != mTargetReserveBase)
|
||||
{
|
||||
WriteLog (lsINFO, Features) << "Voting for base resrve of " << mTargetReserveBase;
|
||||
baseValidation.setFieldU32 (sfReserveBase, mTargetReserveBase);
|
||||
}
|
||||
|
||||
if (lastClosedLedger->getReserveInc () != mTargetReserveIncrement)
|
||||
{
|
||||
WriteLog (lsINFO, Features) << "Voting for reserve increment of " << mTargetReserveIncrement;
|
||||
baseValidation.setFieldU32 (sfReserveIncrement, mTargetReserveIncrement);
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
void doVoting (Ledger::ref lastClosedLedger, SHAMap::ref initialPosition)
|
||||
{
|
||||
// LCL must be flag ledger
|
||||
assert ((lastClosedLedger->getLedgerSeq () % 256) == 0);
|
||||
|
||||
VotableInteger<uint64> baseFeeVote (lastClosedLedger->getBaseFee (), mTargetBaseFee);
|
||||
VotableInteger<uint32> baseReserveVote (lastClosedLedger->getReserve (0), mTargetReserveBase);
|
||||
VotableInteger<uint32> incReserveVote (lastClosedLedger->getReserveInc (), mTargetReserveIncrement);
|
||||
|
||||
// get validations for ledger before flag
|
||||
ValidationSet set = getApp().getValidations ().getValidations (lastClosedLedger->getParentHash ());
|
||||
BOOST_FOREACH (ValidationSet::value_type const & value, set)
|
||||
{
|
||||
SerializedValidation const& val = *value.second;
|
||||
|
||||
if (val.isTrusted ())
|
||||
{
|
||||
if (val.isFieldPresent (sfBaseFee))
|
||||
{
|
||||
baseFeeVote.addVote (val.getFieldU64 (sfBaseFee));
|
||||
}
|
||||
else
|
||||
{
|
||||
baseFeeVote.noVote ();
|
||||
}
|
||||
|
||||
if (val.isFieldPresent (sfReserveBase))
|
||||
{
|
||||
baseReserveVote.addVote (val.getFieldU32 (sfReserveBase));
|
||||
}
|
||||
else
|
||||
{
|
||||
baseReserveVote.noVote ();
|
||||
}
|
||||
|
||||
if (val.isFieldPresent (sfReserveIncrement))
|
||||
{
|
||||
incReserveVote.addVote (val.getFieldU32 (sfReserveIncrement));
|
||||
}
|
||||
else
|
||||
{
|
||||
incReserveVote.noVote ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// choose our positions
|
||||
uint64 baseFee = baseFeeVote.getVotes ();
|
||||
uint32 baseReserve = baseReserveVote.getVotes ();
|
||||
uint32 incReserve = incReserveVote.getVotes ();
|
||||
|
||||
// add transactions to our position
|
||||
if ((baseFee != lastClosedLedger->getBaseFee ()) ||
|
||||
(baseReserve != lastClosedLedger->getReserve (0)) ||
|
||||
(incReserve != lastClosedLedger->getReserveInc ()))
|
||||
{
|
||||
WriteLog (lsWARNING, Features) << "We are voting for a fee change: " << baseFee << "/" << baseReserve << "/" << incReserve;
|
||||
|
||||
SerializedTransaction trans (ttFEE);
|
||||
trans.setFieldAccount (sfAccount, uint160 ());
|
||||
trans.setFieldU64 (sfBaseFee, baseFee);
|
||||
trans.setFieldU32 (sfReferenceFeeUnits, 10);
|
||||
trans.setFieldU32 (sfReserveBase, baseReserve);
|
||||
trans.setFieldU32 (sfReserveIncrement, incReserve);
|
||||
|
||||
uint256 txID = trans.getTransactionID ();
|
||||
|
||||
WriteLog (lsWARNING, Features) << "Vote: " << txID;
|
||||
|
||||
Serializer s;
|
||||
trans.add (s, true);
|
||||
|
||||
SHAMapItem::pointer tItem = boost::make_shared<SHAMapItem> (txID, s.peekData ());
|
||||
|
||||
if (!initialPosition->addGiveItem (tItem, true, false))
|
||||
{
|
||||
WriteLog (lsWARNING, Features) << "Ledger already had fee change";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
uint64 mTargetBaseFee;
|
||||
uint32 mTargetReserveBase;
|
||||
uint32 mTargetReserveIncrement;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
IFeeVote* IFeeVote::New (uint64 targetBaseFee,
|
||||
uint32 targetReserveBase,
|
||||
uint32 targetReserveIncrement)
|
||||
{
|
||||
return new FeeVote (targetBaseFee, targetReserveBase, targetReserveIncrement);
|
||||
}
|
||||
|
||||
// vim:ts=4
|
||||
229
src/ripple_app/misc/ripple_HashRouter.cpp
Normal file
229
src/ripple_app/misc/ripple_HashRouter.cpp
Normal file
@@ -0,0 +1,229 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (c) 2011-2013, OpenCoin, Inc.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
// VFALCO TODO Inline the function definitions
|
||||
class HashRouter : public IHashRouter
|
||||
{
|
||||
private:
|
||||
/** An entry in the routing table.
|
||||
*/
|
||||
class Entry : public CountedObject <Entry>
|
||||
{
|
||||
public:
|
||||
static char const* getCountedObjectName () { return "HashRouterEntry"; }
|
||||
|
||||
Entry ()
|
||||
: mFlags (0)
|
||||
{
|
||||
}
|
||||
|
||||
std::set <uint64> const& peekPeers () const
|
||||
{
|
||||
return mPeers;
|
||||
}
|
||||
|
||||
void addPeer (uint64 peer)
|
||||
{
|
||||
if (peer != 0)
|
||||
mPeers.insert (peer);
|
||||
}
|
||||
|
||||
bool hasPeer (uint64 peer) const
|
||||
{
|
||||
return mPeers.count (peer) > 0;
|
||||
}
|
||||
|
||||
int getFlags (void) const
|
||||
{
|
||||
return mFlags;
|
||||
}
|
||||
|
||||
bool hasFlag (int mask) const
|
||||
{
|
||||
return (mFlags & mask) != 0;
|
||||
}
|
||||
|
||||
void setFlag (int flagsToSet)
|
||||
{
|
||||
mFlags |= flagsToSet;
|
||||
}
|
||||
|
||||
void clearFlag (int flagsToClear)
|
||||
{
|
||||
mFlags &= ~flagsToClear;
|
||||
}
|
||||
|
||||
void swapSet (std::set <uint64>& other)
|
||||
{
|
||||
mPeers.swap (other);
|
||||
}
|
||||
|
||||
private:
|
||||
int mFlags;
|
||||
std::set <uint64> mPeers;
|
||||
};
|
||||
|
||||
public:
|
||||
explicit HashRouter (int holdTime)
|
||||
: mLock (this, "HashRouter", __FILE__, __LINE__)
|
||||
, mHoldTime (holdTime)
|
||||
{
|
||||
}
|
||||
|
||||
bool addSuppression (uint256 const& index);
|
||||
|
||||
bool addSuppressionPeer (uint256 const& index, uint64 peer);
|
||||
bool addSuppressionPeer (uint256 const& index, uint64 peer, int& flags);
|
||||
bool addSuppressionFlags (uint256 const& index, int flag);
|
||||
bool setFlag (uint256 const& index, int flag);
|
||||
int getFlags (uint256 const& index);
|
||||
|
||||
bool swapSet (uint256 const& index, std::set<uint64>& peers, int flag);
|
||||
|
||||
private:
|
||||
Entry getEntry (uint256 const& );
|
||||
|
||||
Entry& findCreateEntry (uint256 const& , bool& created);
|
||||
|
||||
typedef RippleMutex LockType;
|
||||
typedef LockType::ScopedLockType ScopedLockType;
|
||||
LockType mLock;
|
||||
|
||||
// Stores all suppressed hashes and their expiration time
|
||||
boost::unordered_map <uint256, Entry> mSuppressionMap;
|
||||
|
||||
// Stores all expiration times and the hashes indexed for them
|
||||
std::map< int, std::list<uint256> > mSuppressionTimes;
|
||||
|
||||
int mHoldTime;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
HashRouter::Entry& HashRouter::findCreateEntry (uint256 const& index, bool& created)
|
||||
{
|
||||
boost::unordered_map<uint256, Entry>::iterator fit = mSuppressionMap.find (index);
|
||||
|
||||
if (fit != mSuppressionMap.end ())
|
||||
{
|
||||
created = false;
|
||||
return fit->second;
|
||||
}
|
||||
|
||||
created = true;
|
||||
|
||||
int now = UptimeTimer::getInstance ().getElapsedSeconds ();
|
||||
int expireTime = now - mHoldTime;
|
||||
|
||||
// See if any supressions need to be expired
|
||||
std::map< int, std::list<uint256> >::iterator it = mSuppressionTimes.begin ();
|
||||
|
||||
if ((it != mSuppressionTimes.end ()) && (it->first <= expireTime))
|
||||
{
|
||||
BOOST_FOREACH (uint256 const & lit, it->second)
|
||||
mSuppressionMap.erase (lit);
|
||||
mSuppressionTimes.erase (it);
|
||||
}
|
||||
|
||||
mSuppressionTimes[now].push_back (index);
|
||||
return mSuppressionMap.emplace (index, Entry ()).first->second;
|
||||
}
|
||||
|
||||
bool HashRouter::addSuppression (uint256 const& index)
|
||||
{
|
||||
ScopedLockType sl (mLock, __FILE__, __LINE__);
|
||||
|
||||
bool created;
|
||||
findCreateEntry (index, created);
|
||||
return created;
|
||||
}
|
||||
|
||||
HashRouter::Entry HashRouter::getEntry (uint256 const& index)
|
||||
{
|
||||
ScopedLockType sl (mLock, __FILE__, __LINE__);
|
||||
|
||||
bool created;
|
||||
return findCreateEntry (index, created);
|
||||
}
|
||||
|
||||
bool HashRouter::addSuppressionPeer (uint256 const& index, uint64 peer)
|
||||
{
|
||||
ScopedLockType sl (mLock, __FILE__, __LINE__);
|
||||
|
||||
bool created;
|
||||
findCreateEntry (index, created).addPeer (peer);
|
||||
return created;
|
||||
}
|
||||
|
||||
bool HashRouter::addSuppressionPeer (uint256 const& index, uint64 peer, int& flags)
|
||||
{
|
||||
ScopedLockType sl (mLock, __FILE__, __LINE__);
|
||||
|
||||
bool created;
|
||||
Entry& s = findCreateEntry (index, created);
|
||||
s.addPeer (peer);
|
||||
flags = s.getFlags ();
|
||||
return created;
|
||||
}
|
||||
|
||||
int HashRouter::getFlags (uint256 const& index)
|
||||
{
|
||||
ScopedLockType sl (mLock, __FILE__, __LINE__);
|
||||
|
||||
bool created;
|
||||
return findCreateEntry (index, created).getFlags ();
|
||||
}
|
||||
|
||||
bool HashRouter::addSuppressionFlags (uint256 const& index, int flag)
|
||||
{
|
||||
ScopedLockType sl (mLock, __FILE__, __LINE__);
|
||||
|
||||
bool created;
|
||||
findCreateEntry (index, created).setFlag (flag);
|
||||
return created;
|
||||
}
|
||||
|
||||
bool HashRouter::setFlag (uint256 const& index, int flag)
|
||||
{
|
||||
// VFALCO NOTE Comments like this belong in the HEADER file,
|
||||
// and more importantly in a Javadoc comment so
|
||||
// they appear in the generated documentation.
|
||||
//
|
||||
// return: true = changed, false = unchanged
|
||||
assert (flag != 0);
|
||||
|
||||
ScopedLockType sl (mLock, __FILE__, __LINE__);
|
||||
|
||||
bool created;
|
||||
Entry& s = findCreateEntry (index, created);
|
||||
|
||||
if ((s.getFlags () & flag) == flag)
|
||||
return false;
|
||||
|
||||
s.setFlag (flag);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HashRouter::swapSet (uint256 const& index, std::set<uint64>& peers, int flag)
|
||||
{
|
||||
ScopedLockType sl (mLock, __FILE__, __LINE__);
|
||||
|
||||
bool created;
|
||||
Entry& s = findCreateEntry (index, created);
|
||||
|
||||
if ((s.getFlags () & flag) == flag)
|
||||
return false;
|
||||
|
||||
s.swapSet (peers);
|
||||
s.setFlag (flag);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
IHashRouter* IHashRouter::New (int holdTime)
|
||||
{
|
||||
return new HashRouter (holdTime);
|
||||
}
|
||||
130
src/ripple_app/misc/ripple_IFeatures.h
Normal file
130
src/ripple_app/misc/ripple_IFeatures.h
Normal file
@@ -0,0 +1,130 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (c) 2011-2013, OpenCoin, Inc.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef RIPPLE_IFEATURES_H
|
||||
#define RIPPLE_IFEATURES_H
|
||||
|
||||
class FeatureSet
|
||||
{
|
||||
// the status of all features requested in a given window
|
||||
public:
|
||||
uint32 mCloseTime;
|
||||
int mTrustedValidations; // number of trusted validations
|
||||
boost::unordered_map<uint256, int> mVotes; // yes votes by feature
|
||||
|
||||
FeatureSet (uint32 ct, int tv) : mCloseTime (ct), mTrustedValidations (tv)
|
||||
{
|
||||
;
|
||||
}
|
||||
void addVote (uint256 const& feature)
|
||||
{
|
||||
++mVotes[feature];
|
||||
}
|
||||
};
|
||||
|
||||
class FeatureState
|
||||
{
|
||||
public:
|
||||
bool mVetoed; // We don't want this feature enabled
|
||||
bool mEnabled;
|
||||
bool mSupported;
|
||||
bool mDefault; // Include in genesis ledger
|
||||
|
||||
uint32 mFirstMajority; // First time we saw a majority (close time)
|
||||
uint32 mLastMajority; // Most recent time we saw a majority (close time)
|
||||
|
||||
std::string mFriendlyName;
|
||||
|
||||
FeatureState ()
|
||||
: mVetoed (false), mEnabled (false), mSupported (false), mDefault (false),
|
||||
mFirstMajority (0), mLastMajority (0)
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
void setVeto ()
|
||||
{
|
||||
mVetoed = true;
|
||||
}
|
||||
void setDefault ()
|
||||
{
|
||||
mDefault = true;
|
||||
}
|
||||
bool isDefault ()
|
||||
{
|
||||
return mDefault;
|
||||
}
|
||||
bool isSupported ()
|
||||
{
|
||||
return mSupported;
|
||||
}
|
||||
bool isVetoed ()
|
||||
{
|
||||
return mVetoed;
|
||||
}
|
||||
bool isEnabled ()
|
||||
{
|
||||
return mEnabled;
|
||||
}
|
||||
const std::string& getFiendlyName ()
|
||||
{
|
||||
return mFriendlyName;
|
||||
}
|
||||
void setFriendlyName (const std::string& n)
|
||||
{
|
||||
mFriendlyName = n;
|
||||
}
|
||||
};
|
||||
|
||||
/** Feature table interface.
|
||||
|
||||
The feature table stores the list of enabled and potential features.
|
||||
Individuals features are voted on by validators during the consensus
|
||||
process.
|
||||
*/
|
||||
class IFeatures
|
||||
{
|
||||
public:
|
||||
static IFeatures* New (uint32 majorityTime, int majorityFraction);
|
||||
|
||||
virtual ~IFeatures () { }
|
||||
|
||||
virtual void addInitialFeatures () = 0;
|
||||
|
||||
virtual FeatureState* addKnownFeature (const char* featureID, const char* friendlyName, bool veto) = 0;
|
||||
virtual uint256 getFeature (const std::string& name) = 0;
|
||||
|
||||
virtual bool vetoFeature (uint256 const& feature) = 0;
|
||||
virtual bool unVetoFeature (uint256 const& feature) = 0;
|
||||
|
||||
virtual bool enableFeature (uint256 const& feature) = 0;
|
||||
virtual bool disableFeature (uint256 const& feature) = 0;
|
||||
|
||||
virtual bool isFeatureEnabled (uint256 const& feature) = 0;
|
||||
virtual bool isFeatureSupported (uint256 const& feature) = 0;
|
||||
|
||||
virtual void setEnabledFeatures (const std::vector<uint256>& features) = 0;
|
||||
virtual void setSupportedFeatures (const std::vector<uint256>& features) = 0;
|
||||
|
||||
// VFALCO NOTE these can't possibly be used since featureList_t was/is private.
|
||||
/*
|
||||
featureList_t getVetoedFeatures() = 0;
|
||||
featureList_t getEnabledFeatures() = 0;
|
||||
featureList_t getFeaturesToEnable(uint32 closeTime) = 0; // gets features we would vote to enable
|
||||
featureList_t getDesiredFeatures() = 0; // features we support, do not veto, are not enabled
|
||||
*/
|
||||
|
||||
virtual void reportValidations (const FeatureSet&) = 0;
|
||||
|
||||
virtual Json::Value getJson (int) = 0;
|
||||
virtual Json::Value getJson (uint256 const& ) = 0;
|
||||
|
||||
virtual void doValidation (Ledger::ref lastClosedLedger, STObject& baseValidation) = 0;
|
||||
virtual void doVoting (Ledger::ref lastClosedLedger, SHAMap::ref initialPosition) = 0;
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
44
src/ripple_app/misc/ripple_IFeeVote.h
Normal file
44
src/ripple_app/misc/ripple_IFeeVote.h
Normal file
@@ -0,0 +1,44 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (c) 2011-2013, OpenCoin, Inc.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef RIPPLE_IFEEVOTE_H
|
||||
#define RIPPLE_IFEEVOTE_H
|
||||
|
||||
/** Manager to process fee votes.
|
||||
*/
|
||||
class IFeeVote
|
||||
{
|
||||
public:
|
||||
/** Create a new fee vote manager.
|
||||
|
||||
@param targetBaseFee
|
||||
@param targetReserveBase
|
||||
@param targetReserveIncrement
|
||||
*/
|
||||
static IFeeVote* New (uint64 targetBaseFee,
|
||||
uint32 targetReserveBase,
|
||||
uint32 targetReserveIncrement);
|
||||
|
||||
virtual ~IFeeVote () { }
|
||||
|
||||
/** Add local fee preference to validation.
|
||||
|
||||
@param lastClosedLedger
|
||||
@param baseValidation
|
||||
*/
|
||||
virtual void doValidation (Ledger::ref lastClosedLedger,
|
||||
STObject& baseValidation) = 0;
|
||||
|
||||
/** Cast our local vote on the fee.
|
||||
|
||||
@param lastClosedLedger
|
||||
@param initialPosition
|
||||
*/
|
||||
virtual void doVoting (Ledger::ref lastClosedLedger,
|
||||
SHAMap::ref initialPosition) = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
68
src/ripple_app/misc/ripple_IHashRouter.h
Normal file
68
src/ripple_app/misc/ripple_IHashRouter.h
Normal file
@@ -0,0 +1,68 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (c) 2011-2013, OpenCoin, Inc.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef RIPPLE_HASHROUTER_RIPPLEHEADER
|
||||
#define RIPPLE_HASHROUTER_RIPPLEHEADER
|
||||
|
||||
// VFALCO NOTE Are these the flags?? Why aren't we using a packed struct?
|
||||
// VFALCO TODO convert these macros to int constants
|
||||
#define SF_RELAYED 0x01 // Has already been relayed to other nodes
|
||||
// VFALCO NOTE How can both bad and good be set on a hash?
|
||||
#define SF_BAD 0x02 // Signature/format is bad
|
||||
#define SF_SIGGOOD 0x04 // Signature is good
|
||||
#define SF_SAVED 0x08
|
||||
#define SF_RETRY 0x10 // Transaction can be retried
|
||||
#define SF_TRUSTED 0x20 // comes from trusted source
|
||||
|
||||
/** Routing table for objects identified by hash.
|
||||
|
||||
This table keeps track of which hashes have been received by which peers.
|
||||
It is used to manage the routing and broadcasting of messages in the peer
|
||||
to peer overlay.
|
||||
*/
|
||||
class IHashRouter
|
||||
{
|
||||
public:
|
||||
// VFALCO NOTE this preferred alternative to default parameters makes
|
||||
// behavior clear.
|
||||
//
|
||||
static inline int getDefaultHoldTime ()
|
||||
{
|
||||
return 300;
|
||||
}
|
||||
|
||||
// VFALCO TODO rename the parameter to entryHoldTimeInSeconds
|
||||
static IHashRouter* New (int holdTime);
|
||||
|
||||
virtual ~IHashRouter () { }
|
||||
|
||||
// VFALCO TODO Replace "Supression" terminology with something more semantically meaningful.
|
||||
virtual bool addSuppression (uint256 const& index) = 0;
|
||||
|
||||
virtual bool addSuppressionPeer (uint256 const& index, uint64 peer) = 0;
|
||||
|
||||
virtual bool addSuppressionPeer (uint256 const& index, uint64 peer, int& flags) = 0;
|
||||
|
||||
virtual bool addSuppressionFlags (uint256 const& index, int flag) = 0;
|
||||
|
||||
/** Set the flags on a hash.
|
||||
|
||||
@return `true` if the flags were changed.
|
||||
*/
|
||||
// VFALCO TODO Rename to setFlags since it works with multiple flags.
|
||||
virtual bool setFlag (uint256 const& index, int mask) = 0;
|
||||
|
||||
virtual int getFlags (uint256 const& index) = 0;
|
||||
|
||||
virtual bool swapSet (uint256 const& index, std::set<uint64>& peers, int flag) = 0;
|
||||
|
||||
// VFALCO TODO This appears to be unused!
|
||||
//
|
||||
// virtual Entry getEntry (uint256 const&) = 0;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
33
src/ripple_app/misc/ripple_NicknameState.cpp
Normal file
33
src/ripple_app/misc/ripple_NicknameState.cpp
Normal file
@@ -0,0 +1,33 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (c) 2011-2013, OpenCoin, Inc.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
NicknameState::NicknameState (SerializedLedgerEntry::pointer ledgerEntry) :
|
||||
mLedgerEntry (ledgerEntry)
|
||||
{
|
||||
if (!mLedgerEntry || mLedgerEntry->getType () != ltNICKNAME) return;
|
||||
}
|
||||
|
||||
bool NicknameState::haveMinimumOffer () const
|
||||
{
|
||||
return mLedgerEntry->isFieldPresent (sfMinimumOffer);
|
||||
}
|
||||
|
||||
STAmount NicknameState::getMinimumOffer () const
|
||||
{
|
||||
return mLedgerEntry->isFieldPresent (sfMinimumOffer)
|
||||
? mLedgerEntry->getFieldAmount (sfMinimumOffer)
|
||||
: STAmount ();
|
||||
}
|
||||
|
||||
RippleAddress NicknameState::getAccountID () const
|
||||
{
|
||||
return mLedgerEntry->getFieldAccount (sfAccount);
|
||||
}
|
||||
|
||||
void NicknameState::addJson (Json::Value& val)
|
||||
{
|
||||
val = mLedgerEntry->getJson (0);
|
||||
}
|
||||
49
src/ripple_app/misc/ripple_NicknameState.h
Normal file
49
src/ripple_app/misc/ripple_NicknameState.h
Normal file
@@ -0,0 +1,49 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (c) 2011-2013, OpenCoin, Inc.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
|
||||
#ifndef RIPPLE_NICKNAMESTATE_H
|
||||
#define RIPPLE_NICKNAMESTATE_H
|
||||
|
||||
//
|
||||
// State of a nickname node.
|
||||
// - Isolate ledger entry format.
|
||||
//
|
||||
|
||||
class NicknameState
|
||||
{
|
||||
public:
|
||||
typedef boost::shared_ptr <NicknameState> pointer;
|
||||
|
||||
public:
|
||||
explicit NicknameState (SerializedLedgerEntry::pointer ledgerEntry); // For accounts in a ledger
|
||||
|
||||
bool haveMinimumOffer () const;
|
||||
STAmount getMinimumOffer () const;
|
||||
RippleAddress getAccountID () const;
|
||||
|
||||
SerializedLedgerEntry::pointer getSLE ()
|
||||
{
|
||||
return mLedgerEntry;
|
||||
}
|
||||
const SerializedLedgerEntry& peekSLE () const
|
||||
{
|
||||
return *mLedgerEntry;
|
||||
}
|
||||
SerializedLedgerEntry& peekSLE ()
|
||||
{
|
||||
return *mLedgerEntry;
|
||||
}
|
||||
|
||||
Blob getRaw () const;
|
||||
void addJson (Json::Value& value);
|
||||
|
||||
private:
|
||||
SerializedLedgerEntry::pointer mLedgerEntry;
|
||||
};
|
||||
|
||||
#endif
|
||||
// vim:ts=4
|
||||
33
src/ripple_app/misc/ripple_Offer.cpp
Normal file
33
src/ripple_app/misc/ripple_Offer.cpp
Normal file
@@ -0,0 +1,33 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (c) 2011-2013, OpenCoin, Inc.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
AccountItem::pointer Offer::makeItem (const uint160& , SerializedLedgerEntry::ref ledgerEntry)
|
||||
{
|
||||
if (!ledgerEntry || ledgerEntry->getType () != ltOFFER) return (AccountItem::pointer ());
|
||||
|
||||
Offer* offer = new Offer (ledgerEntry);
|
||||
return (AccountItem::pointer (offer));
|
||||
}
|
||||
|
||||
Offer::Offer (SerializedLedgerEntry::pointer ledgerEntry) : AccountItem (ledgerEntry),
|
||||
mAccount (mLedgerEntry->getFieldAccount (sfAccount)),
|
||||
mTakerGets (mLedgerEntry->getFieldAmount (sfTakerGets)),
|
||||
mTakerPays (mLedgerEntry->getFieldAmount (sfTakerPays)),
|
||||
mSeq (mLedgerEntry->getFieldU32 (sfSequence))
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
Json::Value Offer::getJson (int)
|
||||
{
|
||||
Json::Value ret (Json::objectValue);
|
||||
ret["account"] = mAccount.humanAccountID ();
|
||||
ret["taker_gets"] = getTakerGets ().getFullText ();
|
||||
ret["taker_pays"] = getTakerPays ().getFullText ();
|
||||
return ret;
|
||||
}
|
||||
|
||||
// vim:ts=4
|
||||
55
src/ripple_app/misc/ripple_Offer.h
Normal file
55
src/ripple_app/misc/ripple_Offer.h
Normal file
@@ -0,0 +1,55 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (c) 2011-2013, OpenCoin, Inc.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef RIPPLE_OFFER_H
|
||||
#define RIPPLE_OFFER_H
|
||||
|
||||
class Offer : public AccountItem
|
||||
{
|
||||
public:
|
||||
Offer () {}
|
||||
|
||||
virtual ~Offer () {}
|
||||
|
||||
AccountItem::pointer makeItem (const uint160&, SerializedLedgerEntry::ref ledgerEntry);
|
||||
|
||||
LedgerEntryType getType ()
|
||||
{
|
||||
return (ltOFFER);
|
||||
}
|
||||
|
||||
const STAmount& getTakerPays ()
|
||||
{
|
||||
return (mTakerPays);
|
||||
}
|
||||
const STAmount& getTakerGets ()
|
||||
{
|
||||
return (mTakerGets);
|
||||
}
|
||||
const RippleAddress& getAccount ()
|
||||
{
|
||||
return (mAccount);
|
||||
}
|
||||
int getSeq ()
|
||||
{
|
||||
return (mSeq);
|
||||
}
|
||||
Json::Value getJson (int);
|
||||
|
||||
private:
|
||||
// For accounts in a ledger
|
||||
explicit Offer (SerializedLedgerEntry::pointer ledgerEntry);
|
||||
|
||||
private:
|
||||
RippleAddress mAccount;
|
||||
STAmount mTakerGets;
|
||||
STAmount mTakerPays;
|
||||
int mSeq;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
// vim:ts=4
|
||||
19
src/ripple_app/misc/ripple_OrderBook.cpp
Normal file
19
src/ripple_app/misc/ripple_OrderBook.cpp
Normal file
@@ -0,0 +1,19 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (c) 2011-2013, OpenCoin, Inc.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
|
||||
OrderBook::OrderBook (uint256 const& index,
|
||||
uint160 const& currencyIn,
|
||||
uint160 const& currencyOut,
|
||||
uint160 const& issuerIn,
|
||||
uint160 const& issuerOut)
|
||||
: mBookBase (index)
|
||||
, mCurrencyIn (currencyIn)
|
||||
, mCurrencyOut (currencyOut)
|
||||
, mIssuerIn (issuerIn)
|
||||
, mIssuerOut (issuerOut)
|
||||
{
|
||||
}
|
||||
72
src/ripple_app/misc/ripple_OrderBook.h
Normal file
72
src/ripple_app/misc/ripple_OrderBook.h
Normal file
@@ -0,0 +1,72 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (c) 2011-2013, OpenCoin, Inc.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
|
||||
#ifndef RIPPLE_ORDERBOOK_H
|
||||
#define RIPPLE_ORDERBOOK_H
|
||||
|
||||
/** Describes a serialized ledger entry for an order book.
|
||||
*/
|
||||
class OrderBook : LeakChecked <OrderBook>
|
||||
{
|
||||
public:
|
||||
typedef boost::shared_ptr <OrderBook> pointer;
|
||||
|
||||
typedef boost::shared_ptr <OrderBook> const& ref;
|
||||
|
||||
public:
|
||||
/** Construct from a currency specification.
|
||||
|
||||
@param index ???
|
||||
@param currencyIn The base currency.
|
||||
@param currencyOut The destination currency.
|
||||
@param issuerIn The base issuer.
|
||||
@param issuerOut The destination issuer.
|
||||
*/
|
||||
// VFALCO NOTE what is the meaning of the index parameter?
|
||||
// VFALCO TODO group the issuer and currency parameters together.
|
||||
// VFALCO TODO give typedef names to uint256 / uint160 params
|
||||
OrderBook (uint256 const& index,
|
||||
uint160 const& currencyIn,
|
||||
uint160 const& currencyOut,
|
||||
uint160 const& issuerIn,
|
||||
uint160 const& issuerOut);
|
||||
|
||||
uint256 const& getBookBase () const
|
||||
{
|
||||
return mBookBase;
|
||||
}
|
||||
|
||||
uint160 const& getCurrencyIn () const
|
||||
{
|
||||
return mCurrencyIn;
|
||||
}
|
||||
|
||||
uint160 const& getCurrencyOut () const
|
||||
{
|
||||
return mCurrencyOut;
|
||||
}
|
||||
|
||||
uint160 const& getIssuerIn () const
|
||||
{
|
||||
return mIssuerIn;
|
||||
}
|
||||
|
||||
uint160 const& getIssuerOut () const
|
||||
{
|
||||
return mIssuerOut;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
uint256 const mBookBase;
|
||||
uint160 const mCurrencyIn;
|
||||
uint160 const mCurrencyOut;
|
||||
uint160 const mIssuerIn;
|
||||
uint160 const mIssuerOut;
|
||||
};
|
||||
|
||||
#endif
|
||||
204
src/ripple_app/misc/ripple_SerializedLedger.cpp
Normal file
204
src/ripple_app/misc/ripple_SerializedLedger.cpp
Normal file
@@ -0,0 +1,204 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (c) 2011-2013, OpenCoin, Inc.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
struct SerializedLedgerLog; // for Log
|
||||
|
||||
SETUP_LOGN (SerializedLedgerLog,"SerializedLedger")
|
||||
|
||||
SerializedLedgerEntry::SerializedLedgerEntry (SerializerIterator& sit, uint256 const& index)
|
||||
: STObject (sfLedgerEntry), mIndex (index), mMutable (true)
|
||||
{
|
||||
set (sit);
|
||||
uint16 type = getFieldU16 (sfLedgerEntryType);
|
||||
|
||||
LedgerFormats::Item const* const item =
|
||||
LedgerFormats::getInstance()->findByType (static_cast <LedgerEntryType> (type));
|
||||
|
||||
if (item == nullptr)
|
||||
throw std::runtime_error ("invalid ledger entry type");
|
||||
|
||||
mType = item->getType ();
|
||||
|
||||
if (!setType (item->elements))
|
||||
throw std::runtime_error ("ledger entry not valid for type");
|
||||
}
|
||||
|
||||
SerializedLedgerEntry::SerializedLedgerEntry (const Serializer& s, uint256 const& index)
|
||||
: STObject (sfLedgerEntry), mIndex (index), mMutable (true)
|
||||
{
|
||||
SerializerIterator sit (const_cast<Serializer&> (s)); // we know 's' isn't going away
|
||||
set (sit);
|
||||
|
||||
uint16 type = getFieldU16 (sfLedgerEntryType);
|
||||
|
||||
LedgerFormats::Item const* const item =
|
||||
LedgerFormats::getInstance()->findByType (static_cast <LedgerEntryType> (type));
|
||||
|
||||
if (item == nullptr)
|
||||
throw std::runtime_error ("invalid ledger entry type");
|
||||
|
||||
mType = item->getType ();
|
||||
|
||||
if (!setType (item->elements))
|
||||
{
|
||||
WriteLog (lsWARNING, SerializedLedgerLog) << "Ledger entry not valid for type " << mFormat->getName ();
|
||||
WriteLog (lsWARNING, SerializedLedgerLog) << getJson (0);
|
||||
throw std::runtime_error ("ledger entry not valid for type");
|
||||
}
|
||||
}
|
||||
|
||||
SerializedLedgerEntry::SerializedLedgerEntry (LedgerEntryType type, uint256 const& index) :
|
||||
STObject (sfLedgerEntry), mIndex (index), mType (type), mMutable (true)
|
||||
{
|
||||
LedgerFormats::Item const* const item =
|
||||
LedgerFormats::getInstance()->findByType (type);
|
||||
|
||||
if (item != nullptr)
|
||||
{
|
||||
set (item->elements);
|
||||
|
||||
setFieldU16 (sfLedgerEntryType, static_cast <uint16> (item->getType ()));
|
||||
}
|
||||
else
|
||||
{
|
||||
throw std::runtime_error ("invalid ledger entry type");
|
||||
}
|
||||
}
|
||||
|
||||
SerializedLedgerEntry::pointer SerializedLedgerEntry::getMutable () const
|
||||
{
|
||||
SerializedLedgerEntry::pointer ret = boost::make_shared<SerializedLedgerEntry> (boost::cref (*this));
|
||||
ret->mMutable = true;
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string SerializedLedgerEntry::getFullText () const
|
||||
{
|
||||
std::string ret = "\"";
|
||||
ret += mIndex.GetHex ();
|
||||
ret += "\" = { ";
|
||||
ret += mFormat->getName ();
|
||||
ret += ", ";
|
||||
ret += STObject::getFullText ();
|
||||
ret += "}";
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string SerializedLedgerEntry::getText () const
|
||||
{
|
||||
return str (boost::format ("{ %s, %s }")
|
||||
% mIndex.GetHex ()
|
||||
% STObject::getText ());
|
||||
}
|
||||
|
||||
Json::Value SerializedLedgerEntry::getJson (int options) const
|
||||
{
|
||||
Json::Value ret (STObject::getJson (options));
|
||||
|
||||
ret["index"] = mIndex.GetHex ();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool SerializedLedgerEntry::isThreadedType ()
|
||||
{
|
||||
return getFieldIndex (sfPreviousTxnID) != -1;
|
||||
}
|
||||
|
||||
bool SerializedLedgerEntry::isThreaded ()
|
||||
{
|
||||
return isFieldPresent (sfPreviousTxnID);
|
||||
}
|
||||
|
||||
uint256 SerializedLedgerEntry::getThreadedTransaction ()
|
||||
{
|
||||
return getFieldH256 (sfPreviousTxnID);
|
||||
}
|
||||
|
||||
uint32 SerializedLedgerEntry::getThreadedLedger ()
|
||||
{
|
||||
return getFieldU32 (sfPreviousTxnLgrSeq);
|
||||
}
|
||||
|
||||
bool SerializedLedgerEntry::thread (uint256 const& txID, uint32 ledgerSeq, uint256& prevTxID, uint32& prevLedgerID)
|
||||
{
|
||||
uint256 oldPrevTxID = getFieldH256 (sfPreviousTxnID);
|
||||
WriteLog (lsTRACE, SerializedLedgerLog) << "Thread Tx:" << txID << " prev:" << oldPrevTxID;
|
||||
|
||||
if (oldPrevTxID == txID)
|
||||
{
|
||||
// this transaction is already threaded
|
||||
assert (getFieldU32 (sfPreviousTxnLgrSeq) == ledgerSeq);
|
||||
return false;
|
||||
}
|
||||
|
||||
prevTxID = oldPrevTxID;
|
||||
prevLedgerID = getFieldU32 (sfPreviousTxnLgrSeq);
|
||||
setFieldH256 (sfPreviousTxnID, txID);
|
||||
setFieldU32 (sfPreviousTxnLgrSeq, ledgerSeq);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SerializedLedgerEntry::hasOneOwner ()
|
||||
{
|
||||
return (mType != ltACCOUNT_ROOT) && (getFieldIndex (sfAccount) != -1);
|
||||
}
|
||||
|
||||
bool SerializedLedgerEntry::hasTwoOwners ()
|
||||
{
|
||||
return mType == ltRIPPLE_STATE;
|
||||
}
|
||||
|
||||
RippleAddress SerializedLedgerEntry::getOwner ()
|
||||
{
|
||||
return getFieldAccount (sfAccount);
|
||||
}
|
||||
|
||||
RippleAddress SerializedLedgerEntry::getFirstOwner ()
|
||||
{
|
||||
return RippleAddress::createAccountID (getFieldAmount (sfLowLimit).getIssuer ());
|
||||
}
|
||||
|
||||
RippleAddress SerializedLedgerEntry::getSecondOwner ()
|
||||
{
|
||||
return RippleAddress::createAccountID (getFieldAmount (sfHighLimit).getIssuer ());
|
||||
}
|
||||
|
||||
std::vector<uint256> SerializedLedgerEntry::getOwners ()
|
||||
{
|
||||
std::vector<uint256> owners;
|
||||
uint160 account;
|
||||
|
||||
for (int i = 0, fields = getCount (); i < fields; ++i)
|
||||
{
|
||||
SField::ref fc = getFieldSType (i);
|
||||
|
||||
if ((fc == sfAccount) || (fc == sfOwner))
|
||||
{
|
||||
const STAccount* entry = dynamic_cast<const STAccount*> (peekAtPIndex (i));
|
||||
|
||||
if ((entry != NULL) && entry->getValueH160 (account))
|
||||
owners.push_back (Ledger::getAccountRootIndex (account));
|
||||
}
|
||||
|
||||
if ((fc == sfLowLimit) || (fc == sfHighLimit))
|
||||
{
|
||||
const STAmount* entry = dynamic_cast<const STAmount*> (peekAtPIndex (i));
|
||||
|
||||
if ((entry != NULL))
|
||||
{
|
||||
uint160 issuer = entry->getIssuer ();
|
||||
|
||||
if (issuer.isNonZero ())
|
||||
owners.push_back (Ledger::getAccountRootIndex (issuer));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return owners;
|
||||
}
|
||||
|
||||
// vim:ts=4
|
||||
108
src/ripple_app/misc/ripple_SerializedLedger.h
Normal file
108
src/ripple_app/misc/ripple_SerializedLedger.h
Normal file
@@ -0,0 +1,108 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (c) 2011-2013, OpenCoin, Inc.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef RIPPLE_SERIALIZEDLEDGER_H
|
||||
#define RIPPLE_SERIALIZEDLEDGER_H
|
||||
|
||||
// VFALCO NOTE
|
||||
//
|
||||
// This looks like a central class for Ripple. Almost everything that
|
||||
// does anything of interest deals with SLE objects. Any documentation
|
||||
// effort should start with a complete description of this object and
|
||||
// all of its operations.
|
||||
//
|
||||
// It is derived from STObject so it inherits a lot of behavior from that.
|
||||
//
|
||||
// VFALCO TODO Rename the source file to match the class
|
||||
//
|
||||
// VFALCO TODO Can we rename this class to something shorter and more concise?
|
||||
//
|
||||
// Can we just call this LedgerEntry?
|
||||
//
|
||||
class SerializedLedgerEntry
|
||||
: public STObject
|
||||
, public CountedObject <SerializedLedgerEntry>
|
||||
{
|
||||
public:
|
||||
static char const* getCountedObjectName () { return "SerializedLedgerEntry"; }
|
||||
|
||||
typedef boost::shared_ptr<SerializedLedgerEntry> pointer;
|
||||
typedef const boost::shared_ptr<SerializedLedgerEntry>& ref;
|
||||
|
||||
public:
|
||||
SerializedLedgerEntry (const Serializer & s, uint256 const & index);
|
||||
SerializedLedgerEntry (SerializerIterator & sit, uint256 const & index);
|
||||
SerializedLedgerEntry (LedgerEntryType type, uint256 const & index);
|
||||
|
||||
SerializedTypeID getSType () const
|
||||
{
|
||||
return STI_LEDGERENTRY;
|
||||
}
|
||||
std::string getFullText () const;
|
||||
std::string getText () const;
|
||||
Json::Value getJson (int options) const;
|
||||
|
||||
uint256 const& getIndex () const
|
||||
{
|
||||
return mIndex;
|
||||
}
|
||||
void setIndex (uint256 const & i)
|
||||
{
|
||||
mIndex = i;
|
||||
}
|
||||
|
||||
void setImmutable ()
|
||||
{
|
||||
mMutable = false;
|
||||
}
|
||||
bool isMutable ()
|
||||
{
|
||||
return mMutable;
|
||||
}
|
||||
SerializedLedgerEntry::pointer getMutable () const;
|
||||
|
||||
LedgerEntryType getType () const
|
||||
{
|
||||
return mType;
|
||||
}
|
||||
uint16 getVersion () const
|
||||
{
|
||||
return getFieldU16 (sfLedgerEntryType);
|
||||
}
|
||||
LedgerFormats::Item const* getFormat ()
|
||||
{
|
||||
return mFormat;
|
||||
}
|
||||
|
||||
bool isThreadedType (); // is this a ledger entry that can be threaded
|
||||
bool isThreaded (); // is this ledger entry actually threaded
|
||||
bool hasOneOwner (); // This node has one other node that owns it (like nickname)
|
||||
bool hasTwoOwners (); // This node has two nodes that own it (like ripple balance)
|
||||
RippleAddress getOwner ();
|
||||
RippleAddress getFirstOwner ();
|
||||
RippleAddress getSecondOwner ();
|
||||
uint256 getThreadedTransaction ();
|
||||
uint32 getThreadedLedger ();
|
||||
bool thread (uint256 const & txID, uint32 ledgerSeq, uint256 & prevTxID, uint32 & prevLedgerID);
|
||||
std::vector<uint256> getOwners (); // nodes notified if this node is deleted
|
||||
|
||||
private:
|
||||
SerializedLedgerEntry* duplicate () const
|
||||
{
|
||||
return new SerializedLedgerEntry (*this);
|
||||
}
|
||||
|
||||
private:
|
||||
uint256 mIndex;
|
||||
LedgerEntryType mType;
|
||||
LedgerFormats::Item const* mFormat;
|
||||
bool mMutable;
|
||||
};
|
||||
|
||||
typedef SerializedLedgerEntry SLE;
|
||||
|
||||
#endif
|
||||
// vim:ts=4
|
||||
351
src/ripple_app/misc/ripple_SerializedTransaction.cpp
Normal file
351
src/ripple_app/misc/ripple_SerializedTransaction.cpp
Normal file
@@ -0,0 +1,351 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (c) 2011-2013, OpenCoin, Inc.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
SETUP_LOG (SerializedTransaction)
|
||||
|
||||
SerializedTransaction::SerializedTransaction (TxType type)
|
||||
: STObject (sfTransaction)
|
||||
, mType (type)
|
||||
, mSigGood (false)
|
||||
, mSigBad (false)
|
||||
{
|
||||
mFormat = TxFormats::getInstance()->findByType (type);
|
||||
|
||||
if (mFormat == nullptr)
|
||||
{
|
||||
WriteLog (lsWARNING, SerializedTransaction) << "Transaction type: " << type;
|
||||
throw std::runtime_error ("invalid transaction type");
|
||||
}
|
||||
|
||||
set (mFormat->elements);
|
||||
setFieldU16 (sfTransactionType, mFormat->getType ());
|
||||
}
|
||||
|
||||
SerializedTransaction::SerializedTransaction (STObject const& object)
|
||||
: STObject (object)
|
||||
, mSigGood (false)
|
||||
, mSigBad (false)
|
||||
{
|
||||
mType = static_cast <TxType> (getFieldU16 (sfTransactionType));
|
||||
|
||||
mFormat = TxFormats::getInstance()->findByType (mType);
|
||||
|
||||
if (!mFormat)
|
||||
{
|
||||
WriteLog (lsWARNING, SerializedTransaction) << "Transaction type: " << mType;
|
||||
throw std::runtime_error ("invalid transaction type");
|
||||
}
|
||||
|
||||
if (!setType (mFormat->elements))
|
||||
{
|
||||
throw std::runtime_error ("transaction not valid");
|
||||
}
|
||||
}
|
||||
|
||||
SerializedTransaction::SerializedTransaction (SerializerIterator& sit) : STObject (sfTransaction),
|
||||
mSigGood (false), mSigBad (false)
|
||||
{
|
||||
int length = sit.getBytesLeft ();
|
||||
|
||||
if ((length < Protocol::txMinSizeBytes) || (length > Protocol::txMaxSizeBytes))
|
||||
{
|
||||
Log (lsERROR) << "Transaction has invalid length: " << length;
|
||||
throw std::runtime_error ("Transaction length invalid");
|
||||
}
|
||||
|
||||
set (sit);
|
||||
mType = static_cast<TxType> (getFieldU16 (sfTransactionType));
|
||||
|
||||
mFormat = TxFormats::getInstance()->findByType (mType);
|
||||
|
||||
if (!mFormat)
|
||||
{
|
||||
WriteLog (lsWARNING, SerializedTransaction) << "Transaction type: " << mType;
|
||||
throw std::runtime_error ("invalid transaction type");
|
||||
}
|
||||
|
||||
if (!setType (mFormat->elements))
|
||||
{
|
||||
WriteLog (lsWARNING, SerializedTransaction) << "Transaction not legal for format";
|
||||
throw std::runtime_error ("transaction not valid");
|
||||
}
|
||||
}
|
||||
|
||||
std::string SerializedTransaction::getFullText () const
|
||||
{
|
||||
std::string ret = "\"";
|
||||
ret += getTransactionID ().GetHex ();
|
||||
ret += "\" = {";
|
||||
ret += STObject::getFullText ();
|
||||
ret += "}";
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string SerializedTransaction::getText () const
|
||||
{
|
||||
return STObject::getText ();
|
||||
}
|
||||
|
||||
std::vector<RippleAddress> SerializedTransaction::getMentionedAccounts () const
|
||||
{
|
||||
std::vector<RippleAddress> accounts;
|
||||
|
||||
BOOST_FOREACH (const SerializedType & it, peekData ())
|
||||
{
|
||||
const STAccount* sa = dynamic_cast<const STAccount*> (&it);
|
||||
|
||||
if (sa != NULL)
|
||||
{
|
||||
bool found = false;
|
||||
RippleAddress na = sa->getValueNCA ();
|
||||
BOOST_FOREACH (const RippleAddress & it, accounts)
|
||||
{
|
||||
if (it == na)
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found)
|
||||
accounts.push_back (na);
|
||||
}
|
||||
|
||||
const STAmount* sam = dynamic_cast<const STAmount*> (&it);
|
||||
|
||||
if (sam)
|
||||
{
|
||||
uint160 issuer = sam->getIssuer ();
|
||||
|
||||
if (issuer.isNonZero ())
|
||||
{
|
||||
RippleAddress na;
|
||||
na.setAccountID (issuer);
|
||||
bool found = false;
|
||||
BOOST_FOREACH (const RippleAddress & it, accounts)
|
||||
{
|
||||
if (it == na)
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found)
|
||||
accounts.push_back (na);
|
||||
}
|
||||
}
|
||||
}
|
||||
return accounts;
|
||||
}
|
||||
|
||||
uint256 SerializedTransaction::getSigningHash () const
|
||||
{
|
||||
return STObject::getSigningHash (getConfig ().SIGN_TRANSACTION);
|
||||
}
|
||||
|
||||
uint256 SerializedTransaction::getTransactionID () const
|
||||
{
|
||||
// perhaps we should cache this
|
||||
return getHash (HashPrefix::transactionID);
|
||||
}
|
||||
|
||||
Blob SerializedTransaction::getSignature () const
|
||||
{
|
||||
try
|
||||
{
|
||||
return getFieldVL (sfTxnSignature);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
return Blob ();
|
||||
}
|
||||
}
|
||||
|
||||
void SerializedTransaction::sign (const RippleAddress& naAccountPrivate)
|
||||
{
|
||||
Blob signature;
|
||||
naAccountPrivate.accountPrivateSign (getSigningHash (), signature);
|
||||
setFieldVL (sfTxnSignature, signature);
|
||||
}
|
||||
|
||||
bool SerializedTransaction::checkSign () const
|
||||
{
|
||||
if (mSigGood)
|
||||
return true;
|
||||
|
||||
if (mSigBad)
|
||||
return false;
|
||||
|
||||
try
|
||||
{
|
||||
RippleAddress n;
|
||||
n.setAccountPublic (getFieldVL (sfSigningPubKey));
|
||||
|
||||
if (checkSign (n))
|
||||
{
|
||||
mSigGood = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
mSigBad = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SerializedTransaction::checkSign (const RippleAddress& naAccountPublic) const
|
||||
{
|
||||
try
|
||||
{
|
||||
return naAccountPublic.accountPublicVerify (getSigningHash (), getFieldVL (sfTxnSignature));
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void SerializedTransaction::setSigningPubKey (const RippleAddress& naSignPubKey)
|
||||
{
|
||||
setFieldVL (sfSigningPubKey, naSignPubKey.getAccountPublic ());
|
||||
}
|
||||
|
||||
void SerializedTransaction::setSourceAccount (const RippleAddress& naSource)
|
||||
{
|
||||
setFieldAccount (sfAccount, naSource);
|
||||
}
|
||||
|
||||
Json::Value SerializedTransaction::getJson (int options, bool binary) const
|
||||
{
|
||||
if (binary)
|
||||
{
|
||||
Json::Value ret;
|
||||
Serializer s = STObject::getSerializer ();
|
||||
ret["tx"] = strHex (s.peekData ());
|
||||
ret["hash"] = getTransactionID ().GetHex ();
|
||||
return ret;
|
||||
}
|
||||
|
||||
Json::Value ret = STObject::getJson (0);
|
||||
ret["hash"] = getTransactionID ().GetHex ();
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string SerializedTransaction::getSQLValueHeader ()
|
||||
{
|
||||
return "(TransID, TransType, FromAcct, FromSeq, LedgerSeq, Status, RawTxn)";
|
||||
}
|
||||
|
||||
std::string SerializedTransaction::getMetaSQLValueHeader ()
|
||||
{
|
||||
return "(TransID, TransType, FromAcct, FromSeq, LedgerSeq, Status, RawTxn, TxnMeta)";
|
||||
}
|
||||
|
||||
std::string SerializedTransaction::getMetaSQLInsertReplaceHeader ()
|
||||
{
|
||||
return "INSERT OR REPLACE INTO Transactions " + getMetaSQLValueHeader () + " VALUES ";
|
||||
}
|
||||
|
||||
std::string SerializedTransaction::getSQL (uint32 inLedger, char status) const
|
||||
{
|
||||
Serializer s;
|
||||
add (s);
|
||||
return getSQL (s, inLedger, status);
|
||||
}
|
||||
|
||||
std::string SerializedTransaction::getMetaSQL (uint32 inLedger, const std::string& escapedMetaData) const
|
||||
{
|
||||
Serializer s;
|
||||
add (s);
|
||||
return getMetaSQL (s, inLedger, TXN_SQL_VALIDATED, escapedMetaData);
|
||||
}
|
||||
|
||||
std::string SerializedTransaction::getSQL (Serializer rawTxn, uint32 inLedger, char status) const
|
||||
{
|
||||
static boost::format bfTrans ("('%s', '%s', '%s', '%d', '%d', '%c', %s)");
|
||||
std::string rTxn = sqlEscape (rawTxn.peekData ());
|
||||
|
||||
return str (boost::format (bfTrans)
|
||||
% getTransactionID ().GetHex () % getTransactionType () % getSourceAccount ().humanAccountID ()
|
||||
% getSequence () % inLedger % status % rTxn);
|
||||
}
|
||||
|
||||
std::string SerializedTransaction::getMetaSQL (Serializer rawTxn, uint32 inLedger, char status,
|
||||
const std::string& escapedMetaData) const
|
||||
{
|
||||
static boost::format bfTrans ("('%s', '%s', '%s', '%d', '%d', '%c', %s, %s)");
|
||||
std::string rTxn = sqlEscape (rawTxn.peekData ());
|
||||
|
||||
return str (boost::format (bfTrans)
|
||||
% getTransactionID ().GetHex () % getTransactionType () % getSourceAccount ().humanAccountID ()
|
||||
% getSequence () % inLedger % status % rTxn % escapedMetaData);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class SerializedTransactionTests : public UnitTest
|
||||
{
|
||||
public:
|
||||
SerializedTransactionTests () : UnitTest ("SerializedTransaction", "ripple")
|
||||
{
|
||||
}
|
||||
|
||||
void runTest ()
|
||||
{
|
||||
beginTestCase ("tx");
|
||||
|
||||
RippleAddress seed;
|
||||
seed.setSeedRandom ();
|
||||
RippleAddress generator = RippleAddress::createGeneratorPublic (seed);
|
||||
RippleAddress publicAcct = RippleAddress::createAccountPublic (generator, 1);
|
||||
RippleAddress privateAcct = RippleAddress::createAccountPrivate (generator, seed, 1);
|
||||
|
||||
SerializedTransaction j (ttACCOUNT_SET);
|
||||
j.setSourceAccount (publicAcct);
|
||||
j.setSigningPubKey (publicAcct);
|
||||
j.setFieldVL (sfMessageKey, publicAcct.getAccountPublic ());
|
||||
j.sign (privateAcct);
|
||||
|
||||
unexpected (!j.checkSign (), "Transaction fails signature test");
|
||||
|
||||
Serializer rawTxn;
|
||||
j.add (rawTxn);
|
||||
SerializerIterator sit (rawTxn);
|
||||
SerializedTransaction copy (sit);
|
||||
|
||||
if (copy != j)
|
||||
{
|
||||
Log (lsFATAL) << j.getJson (0);
|
||||
Log (lsFATAL) << copy.getJson (0);
|
||||
fail ("Transaction fails serialize/deserialize test");
|
||||
}
|
||||
else
|
||||
{
|
||||
pass ();
|
||||
}
|
||||
|
||||
UPTR_T<STObject> new_obj = STObject::parseJson (j.getJson (0), sfGeneric);
|
||||
|
||||
if (new_obj.get () == NULL) fail ("Unable to build object from json");
|
||||
|
||||
if (STObject (j) != *new_obj)
|
||||
{
|
||||
Log (lsINFO) << "ORIG: " << j.getJson (0);
|
||||
Log (lsINFO) << "BUILT " << new_obj->getJson (0);
|
||||
fail ("Built a different transaction");
|
||||
}
|
||||
else
|
||||
{
|
||||
pass ();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
static SerializedTransactionTests serializedTransactionTests;
|
||||
141
src/ripple_app/misc/ripple_SerializedTransaction.h
Normal file
141
src/ripple_app/misc/ripple_SerializedTransaction.h
Normal file
@@ -0,0 +1,141 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (c) 2011-2013, OpenCoin, Inc.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef RIPPLE_SERIALIZEDTRANSACTION_H
|
||||
#define RIPPLE_SERIALIZEDTRANSACTION_H
|
||||
|
||||
// VFALCO TODO eliminate these macros
|
||||
|
||||
#define TXN_SQL_NEW 'N'
|
||||
#define TXN_SQL_CONFLICT 'C'
|
||||
#define TXN_SQL_HELD 'H'
|
||||
#define TXN_SQL_VALIDATED 'V'
|
||||
#define TXN_SQL_INCLUDED 'I'
|
||||
#define TXN_SQL_UNKNOWN 'U'
|
||||
|
||||
class SerializedTransaction
|
||||
: public STObject
|
||||
, public CountedObject <SerializedTransaction>
|
||||
{
|
||||
public:
|
||||
static char const* getCountedObjectName () { return "SerializedTransaction"; }
|
||||
|
||||
typedef boost::shared_ptr<SerializedTransaction> pointer;
|
||||
typedef const boost::shared_ptr<SerializedTransaction>& ref;
|
||||
|
||||
public:
|
||||
SerializedTransaction (SerializerIterator & sit);
|
||||
SerializedTransaction (TxType type);
|
||||
SerializedTransaction (const STObject & object);
|
||||
|
||||
// STObject functions
|
||||
SerializedTypeID getSType () const
|
||||
{
|
||||
return STI_TRANSACTION;
|
||||
}
|
||||
std::string getFullText () const;
|
||||
std::string getText () const;
|
||||
|
||||
// outer transaction functions / signature functions
|
||||
Blob getSignature () const;
|
||||
void setSignature (Blob const & s)
|
||||
{
|
||||
setFieldVL (sfTxnSignature, s);
|
||||
}
|
||||
uint256 getSigningHash () const;
|
||||
|
||||
TxType getTxnType () const
|
||||
{
|
||||
return mType;
|
||||
}
|
||||
STAmount getTransactionFee () const
|
||||
{
|
||||
return getFieldAmount (sfFee);
|
||||
}
|
||||
void setTransactionFee (const STAmount & fee)
|
||||
{
|
||||
setFieldAmount (sfFee, fee);
|
||||
}
|
||||
|
||||
RippleAddress getSourceAccount () const
|
||||
{
|
||||
return getFieldAccount (sfAccount);
|
||||
}
|
||||
Blob getSigningPubKey () const
|
||||
{
|
||||
return getFieldVL (sfSigningPubKey);
|
||||
}
|
||||
void setSigningPubKey (const RippleAddress & naSignPubKey);
|
||||
void setSourceAccount (const RippleAddress & naSource);
|
||||
std::string getTransactionType () const
|
||||
{
|
||||
return mFormat->getName ();
|
||||
}
|
||||
|
||||
uint32 getSequence () const
|
||||
{
|
||||
return getFieldU32 (sfSequence);
|
||||
}
|
||||
void setSequence (uint32 seq)
|
||||
{
|
||||
return setFieldU32 (sfSequence, seq);
|
||||
}
|
||||
|
||||
std::vector<RippleAddress> getMentionedAccounts () const;
|
||||
|
||||
uint256 getTransactionID () const;
|
||||
|
||||
virtual Json::Value getJson (int options, bool binary = false) const;
|
||||
|
||||
void sign (const RippleAddress & naAccountPrivate);
|
||||
bool checkSign (const RippleAddress & naAccountPublic) const;
|
||||
bool checkSign () const;
|
||||
bool isKnownGood () const
|
||||
{
|
||||
return mSigGood;
|
||||
}
|
||||
bool isKnownBad () const
|
||||
{
|
||||
return mSigBad;
|
||||
}
|
||||
void setGood () const
|
||||
{
|
||||
mSigGood = true;
|
||||
}
|
||||
void setBad () const
|
||||
{
|
||||
mSigBad = true;
|
||||
}
|
||||
|
||||
// SQL Functions
|
||||
static std::string getSQLValueHeader ();
|
||||
static std::string getSQLInsertHeader ();
|
||||
static std::string getSQLInsertIgnoreHeader ();
|
||||
std::string getSQL (std::string & sql, uint32 inLedger, char status) const;
|
||||
std::string getSQL (uint32 inLedger, char status) const;
|
||||
std::string getSQL (Serializer rawTxn, uint32 inLedger, char status) const;
|
||||
|
||||
// SQL Functions with metadata
|
||||
static std::string getMetaSQLValueHeader ();
|
||||
static std::string getMetaSQLInsertReplaceHeader ();
|
||||
std::string getMetaSQL (uint32 inLedger, const std::string & escapedMetaData) const;
|
||||
std::string getMetaSQL (Serializer rawTxn, uint32 inLedger, char status, const std::string & escapedMetaData) const;
|
||||
|
||||
private:
|
||||
TxType mType;
|
||||
TxFormats::Item const* mFormat;
|
||||
|
||||
SerializedTransaction* duplicate () const
|
||||
{
|
||||
return new SerializedTransaction (*this);
|
||||
}
|
||||
|
||||
mutable bool mSigGood;
|
||||
mutable bool mSigBad;
|
||||
};
|
||||
|
||||
#endif
|
||||
// vim:ts=4
|
||||
451
src/ripple_app/misc/ripple_Validations.cpp
Normal file
451
src/ripple_app/misc/ripple_Validations.cpp
Normal file
@@ -0,0 +1,451 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (c) 2011-2013, OpenCoin, Inc.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
class ValidationsImp;
|
||||
|
||||
SETUP_LOG (Validations)
|
||||
|
||||
typedef std::map<uint160, SerializedValidation::pointer>::value_type u160_val_pair;
|
||||
typedef boost::shared_ptr<ValidationSet> VSpointer;
|
||||
|
||||
class ValidationsImp : public Validations
|
||||
{
|
||||
private:
|
||||
typedef RippleMutex LockType;
|
||||
typedef LockType::ScopedLockType ScopedLockType;
|
||||
typedef LockType::ScopedUnlockType ScopedUnlockType;
|
||||
LockType mLock;
|
||||
|
||||
TaggedCacheType<uint256, ValidationSet, UptimeTimerAdapter> mValidations;
|
||||
boost::unordered_map<uint160, SerializedValidation::pointer> mCurrentValidations;
|
||||
std::vector<SerializedValidation::pointer> mStaleValidations;
|
||||
|
||||
bool mWriting;
|
||||
|
||||
private:
|
||||
boost::shared_ptr<ValidationSet> findCreateSet (uint256 const& ledgerHash)
|
||||
{
|
||||
VSpointer j = mValidations.fetch (ledgerHash);
|
||||
|
||||
if (!j)
|
||||
{
|
||||
j = boost::make_shared<ValidationSet> ();
|
||||
mValidations.canonicalize (ledgerHash, j);
|
||||
}
|
||||
|
||||
return j;
|
||||
}
|
||||
|
||||
boost::shared_ptr<ValidationSet> findSet (uint256 const& ledgerHash)
|
||||
{
|
||||
return mValidations.fetch (ledgerHash);
|
||||
}
|
||||
|
||||
public:
|
||||
ValidationsImp ()
|
||||
: mLock (this, "Validations", __FILE__, __LINE__)
|
||||
, mValidations ("Validations", 128, 600), mWriting (false)
|
||||
{
|
||||
mStaleValidations.reserve (512);
|
||||
}
|
||||
|
||||
private:
|
||||
bool addValidation (SerializedValidation::ref val, const std::string& source)
|
||||
{
|
||||
RippleAddress signer = val->getSignerPublic ();
|
||||
bool isCurrent = false;
|
||||
|
||||
if (getApp().getUNL ().nodeInUNL (signer) || val->isTrusted ())
|
||||
{
|
||||
val->setTrusted ();
|
||||
uint32 now = getApp().getOPs ().getCloseTimeNC ();
|
||||
uint32 valClose = val->getSignTime ();
|
||||
|
||||
if ((now > (valClose - LEDGER_EARLY_INTERVAL)) && (now < (valClose + LEDGER_VAL_INTERVAL)))
|
||||
isCurrent = true;
|
||||
else
|
||||
{
|
||||
WriteLog (lsWARNING, Validations) << "Received stale validation now=" << now << ", close=" << valClose;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteLog (lsDEBUG, Validations) << "Node " << signer.humanNodePublic () << " not in UNL st=" << val->getSignTime () <<
|
||||
", hash=" << val->getLedgerHash () << ", shash=" << val->getSigningHash () << " src=" << source;
|
||||
}
|
||||
|
||||
uint256 hash = val->getLedgerHash ();
|
||||
uint160 node = signer.getNodeID ();
|
||||
|
||||
{
|
||||
ScopedLockType sl (mLock, __FILE__, __LINE__);
|
||||
|
||||
if (!findCreateSet (hash)->insert (std::make_pair (node, val)).second)
|
||||
return false;
|
||||
|
||||
if (isCurrent)
|
||||
{
|
||||
boost::unordered_map<uint160, SerializedValidation::pointer>::iterator it = mCurrentValidations.find (node);
|
||||
|
||||
if (it == mCurrentValidations.end ())
|
||||
mCurrentValidations.emplace (node, val);
|
||||
else if (!it->second)
|
||||
it->second = val;
|
||||
else if (val->getSignTime () > it->second->getSignTime ())
|
||||
{
|
||||
val->setPreviousHash (it->second->getLedgerHash ());
|
||||
mStaleValidations.push_back (it->second);
|
||||
it->second = val;
|
||||
condWrite ();
|
||||
}
|
||||
else
|
||||
isCurrent = false;
|
||||
}
|
||||
}
|
||||
|
||||
WriteLog (lsDEBUG, Validations) << "Val for " << hash << " from " << signer.humanNodePublic ()
|
||||
<< " added " << (val->isTrusted () ? "trusted/" : "UNtrusted/") << (isCurrent ? "current" : "stale");
|
||||
|
||||
if (val->isTrusted ())
|
||||
getApp().getLedgerMaster ().checkAccept (hash);
|
||||
|
||||
// FIXME: This never forwards untrusted validations
|
||||
return isCurrent;
|
||||
}
|
||||
|
||||
void tune (int size, int age)
|
||||
{
|
||||
mValidations.setTargetSize (size);
|
||||
mValidations.setTargetAge (age);
|
||||
}
|
||||
|
||||
ValidationSet getValidations (uint256 const& ledger)
|
||||
{
|
||||
{
|
||||
ScopedLockType sl (mLock, __FILE__, __LINE__);
|
||||
VSpointer set = findSet (ledger);
|
||||
|
||||
if (set)
|
||||
return *set;
|
||||
}
|
||||
return ValidationSet ();
|
||||
}
|
||||
|
||||
void getValidationCount (uint256 const& ledger, bool currentOnly, int& trusted, int& untrusted)
|
||||
{
|
||||
trusted = untrusted = 0;
|
||||
ScopedLockType sl (mLock, __FILE__, __LINE__);
|
||||
VSpointer set = findSet (ledger);
|
||||
|
||||
if (set)
|
||||
{
|
||||
uint32 now = getApp().getOPs ().getNetworkTimeNC ();
|
||||
BOOST_FOREACH (u160_val_pair & it, *set)
|
||||
{
|
||||
bool isTrusted = it.second->isTrusted ();
|
||||
|
||||
if (isTrusted && currentOnly)
|
||||
{
|
||||
uint32 closeTime = it.second->getSignTime ();
|
||||
|
||||
if ((now < (closeTime - LEDGER_EARLY_INTERVAL)) || (now > (closeTime + LEDGER_VAL_INTERVAL)))
|
||||
isTrusted = false;
|
||||
else
|
||||
{
|
||||
WriteLog (lsTRACE, Validations) << "VC: Untrusted due to time " << ledger;
|
||||
}
|
||||
}
|
||||
|
||||
if (isTrusted)
|
||||
++trusted;
|
||||
else
|
||||
++untrusted;
|
||||
}
|
||||
}
|
||||
|
||||
WriteLog (lsTRACE, Validations) << "VC: " << ledger << "t:" << trusted << " u:" << untrusted;
|
||||
}
|
||||
|
||||
void getValidationTypes (uint256 const& ledger, int& full, int& partial)
|
||||
{
|
||||
full = partial = 0;
|
||||
ScopedLockType sl (mLock, __FILE__, __LINE__);
|
||||
VSpointer set = findSet (ledger);
|
||||
|
||||
if (set)
|
||||
{
|
||||
BOOST_FOREACH (u160_val_pair & it, *set)
|
||||
{
|
||||
if (it.second->isTrusted ())
|
||||
{
|
||||
if (it.second->isFull ())
|
||||
++full;
|
||||
else
|
||||
++partial;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
WriteLog (lsTRACE, Validations) << "VC: " << ledger << "f:" << full << " p:" << partial;
|
||||
}
|
||||
|
||||
|
||||
int getTrustedValidationCount (uint256 const& ledger)
|
||||
{
|
||||
int trusted = 0;
|
||||
ScopedLockType sl (mLock, __FILE__, __LINE__);
|
||||
VSpointer set = findSet (ledger);
|
||||
|
||||
if (set)
|
||||
{
|
||||
BOOST_FOREACH (u160_val_pair & it, *set)
|
||||
{
|
||||
if (it.second->isTrusted ())
|
||||
++trusted;
|
||||
}
|
||||
}
|
||||
|
||||
return trusted;
|
||||
}
|
||||
|
||||
int getFeeAverage (uint256 const& ledger, uint64 ref, uint64& fee)
|
||||
{
|
||||
int trusted = 0;
|
||||
fee = 0;
|
||||
|
||||
ScopedLockType sl (mLock, __FILE__, __LINE__);
|
||||
VSpointer set = findSet (ledger);
|
||||
|
||||
if (set)
|
||||
{
|
||||
BOOST_FOREACH (u160_val_pair & it, *set)
|
||||
{
|
||||
if (it.second->isTrusted ())
|
||||
{
|
||||
++trusted;
|
||||
if (it.second->isFieldPresent(sfLoadFee))
|
||||
fee += it.second->getFieldU32(sfLoadFee);
|
||||
else
|
||||
fee += ref;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (trusted == 0)
|
||||
fee = ref;
|
||||
else
|
||||
fee /= trusted;
|
||||
return trusted;
|
||||
}
|
||||
|
||||
int getNodesAfter (uint256 const& ledger)
|
||||
{
|
||||
// Number of trusted nodes that have moved past this ledger
|
||||
int count = 0;
|
||||
ScopedLockType sl (mLock, __FILE__, __LINE__);
|
||||
BOOST_FOREACH (u160_val_pair & it, mCurrentValidations)
|
||||
{
|
||||
if (it.second->isTrusted () && it.second->isPreviousHash (ledger))
|
||||
++count;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
int getLoadRatio (bool overLoaded)
|
||||
{
|
||||
// how many trusted nodes are able to keep up, higher is better
|
||||
int goodNodes = overLoaded ? 1 : 0;
|
||||
int badNodes = overLoaded ? 0 : 1;
|
||||
{
|
||||
ScopedLockType sl (mLock, __FILE__, __LINE__);
|
||||
BOOST_FOREACH (u160_val_pair & it, mCurrentValidations)
|
||||
{
|
||||
if (it.second->isTrusted ())
|
||||
{
|
||||
if (it.second->isFull ())
|
||||
++goodNodes;
|
||||
else
|
||||
++badNodes;
|
||||
}
|
||||
}
|
||||
}
|
||||
return (goodNodes * 100) / (goodNodes + badNodes);
|
||||
}
|
||||
|
||||
std::list<SerializedValidation::pointer> getCurrentTrustedValidations ()
|
||||
{
|
||||
uint32 cutoff = getApp().getOPs ().getNetworkTimeNC () - LEDGER_VAL_INTERVAL;
|
||||
|
||||
std::list<SerializedValidation::pointer> ret;
|
||||
|
||||
ScopedLockType sl (mLock, __FILE__, __LINE__);
|
||||
boost::unordered_map<uint160, SerializedValidation::pointer>::iterator it = mCurrentValidations.begin ();
|
||||
|
||||
while (it != mCurrentValidations.end ())
|
||||
{
|
||||
if (!it->second) // contains no record
|
||||
it = mCurrentValidations.erase (it);
|
||||
else if (it->second->getSignTime () < cutoff)
|
||||
{
|
||||
// contains a stale record
|
||||
mStaleValidations.push_back (it->second);
|
||||
it->second.reset ();
|
||||
condWrite ();
|
||||
it = mCurrentValidations.erase (it);
|
||||
}
|
||||
else
|
||||
{
|
||||
// contains a live record
|
||||
if (it->second->isTrusted ())
|
||||
ret.push_back (it->second);
|
||||
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
boost::unordered_map<uint256, currentValidationCount>
|
||||
getCurrentValidations (uint256 currentLedger, uint256 priorLedger)
|
||||
{
|
||||
uint32 cutoff = getApp().getOPs ().getNetworkTimeNC () - LEDGER_VAL_INTERVAL;
|
||||
bool valCurrentLedger = currentLedger.isNonZero ();
|
||||
bool valPriorLedger = priorLedger.isNonZero ();
|
||||
|
||||
boost::unordered_map<uint256, currentValidationCount> ret;
|
||||
|
||||
ScopedLockType sl (mLock, __FILE__, __LINE__);
|
||||
boost::unordered_map<uint160, SerializedValidation::pointer>::iterator it = mCurrentValidations.begin ();
|
||||
|
||||
while (it != mCurrentValidations.end ())
|
||||
{
|
||||
if (!it->second) // contains no record
|
||||
it = mCurrentValidations.erase (it);
|
||||
else if (it->second->getSignTime () < cutoff)
|
||||
{
|
||||
// contains a stale record
|
||||
mStaleValidations.push_back (it->second);
|
||||
it->second.reset ();
|
||||
condWrite ();
|
||||
it = mCurrentValidations.erase (it);
|
||||
}
|
||||
else
|
||||
{
|
||||
// contains a live record
|
||||
bool countPreferred = valCurrentLedger && (it->second->getLedgerHash () == currentLedger);
|
||||
|
||||
if (!countPreferred && // allow up to one ledger slip in either direction
|
||||
((valCurrentLedger && it->second->isPreviousHash (currentLedger)) ||
|
||||
(valPriorLedger && (it->second->getLedgerHash () == priorLedger))))
|
||||
{
|
||||
countPreferred = true;
|
||||
WriteLog (lsTRACE, Validations) << "Counting for " << currentLedger << " not " << it->second->getLedgerHash ();
|
||||
}
|
||||
|
||||
currentValidationCount& p = countPreferred ? ret[currentLedger] : ret[it->second->getLedgerHash ()];
|
||||
++ (p.first);
|
||||
uint160 ni = it->second->getNodeID ();
|
||||
|
||||
if (ni > p.second)
|
||||
p.second = ni;
|
||||
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void flush ()
|
||||
{
|
||||
bool anyNew = false;
|
||||
|
||||
WriteLog (lsINFO, Validations) << "Flushing validations";
|
||||
ScopedLockType sl (mLock, __FILE__, __LINE__);
|
||||
BOOST_FOREACH (u160_val_pair & it, mCurrentValidations)
|
||||
{
|
||||
if (it.second)
|
||||
mStaleValidations.push_back (it.second);
|
||||
|
||||
anyNew = true;
|
||||
}
|
||||
mCurrentValidations.clear ();
|
||||
|
||||
if (anyNew)
|
||||
condWrite ();
|
||||
|
||||
while (mWriting)
|
||||
{
|
||||
ScopedUnlockType sul (mLock, __FILE__, __LINE__);
|
||||
boost::this_thread::sleep (boost::posix_time::milliseconds (100));
|
||||
}
|
||||
|
||||
WriteLog (lsDEBUG, Validations) << "Validations flushed";
|
||||
}
|
||||
|
||||
void condWrite ()
|
||||
{
|
||||
if (mWriting)
|
||||
return;
|
||||
|
||||
mWriting = true;
|
||||
getApp().getJobQueue ().addJob (jtWRITE, "Validations::doWrite",
|
||||
BIND_TYPE (&ValidationsImp::doWrite, this, P_1));
|
||||
}
|
||||
|
||||
void doWrite (Job&)
|
||||
{
|
||||
LoadEvent::autoptr event (getApp().getJobQueue ().getLoadEventAP (jtDISK, "ValidationWrite"));
|
||||
boost::format insVal ("INSERT INTO Validations "
|
||||
"(LedgerHash,NodePubKey,SignTime,RawData) VALUES ('%s','%s','%u',%s);");
|
||||
|
||||
ScopedLockType sl (mLock, __FILE__, __LINE__);
|
||||
assert (mWriting);
|
||||
|
||||
while (!mStaleValidations.empty ())
|
||||
{
|
||||
std::vector<SerializedValidation::pointer> vector;
|
||||
vector.reserve (512);
|
||||
mStaleValidations.swap (vector);
|
||||
|
||||
{
|
||||
ScopedUnlockType sul (mLock, __FILE__, __LINE__);
|
||||
{
|
||||
Database* db = getApp().getLedgerDB ()->getDB ();
|
||||
DeprecatedScopedLock dbl (getApp().getLedgerDB ()->getDBLock ());
|
||||
|
||||
Serializer s (1024);
|
||||
db->executeSQL ("BEGIN TRANSACTION;");
|
||||
BOOST_FOREACH (SerializedValidation::ref it, vector)
|
||||
{
|
||||
s.erase ();
|
||||
it->add (s);
|
||||
db->executeSQL (boost::str (insVal % it->getLedgerHash ().GetHex ()
|
||||
% it->getSignerPublic ().humanNodePublic () % it->getSignTime ()
|
||||
% sqlEscape (s.peekData ())));
|
||||
}
|
||||
db->executeSQL ("END TRANSACTION;");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mWriting = false;
|
||||
}
|
||||
|
||||
void sweep ()
|
||||
{
|
||||
ScopedLockType sl (mLock, __FILE__, __LINE__);
|
||||
mValidations.sweep ();
|
||||
}
|
||||
};
|
||||
|
||||
Validations* Validations::New ()
|
||||
{
|
||||
return new ValidationsImp;
|
||||
}
|
||||
|
||||
// vim:ts=4
|
||||
48
src/ripple_app/misc/ripple_Validations.h
Normal file
48
src/ripple_app/misc/ripple_Validations.h
Normal file
@@ -0,0 +1,48 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
Copyright (c) 2011-2013, OpenCoin, Inc.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef RIPPLE_VALIDATIONS_H_INCLUDED
|
||||
#define RIPPLE_VALIDATIONS_H_INCLUDED
|
||||
|
||||
// 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 Validations : LeakChecked <Validations>
|
||||
{
|
||||
public:
|
||||
static Validations* New ();
|
||||
|
||||
virtual ~Validations () { }
|
||||
|
||||
virtual bool addValidation (SerializedValidation::ref, const std::string& source) = 0;
|
||||
|
||||
virtual ValidationSet getValidations (uint256 const& ledger) = 0;
|
||||
|
||||
virtual void getValidationCount (uint256 const& ledger, bool currentOnly, int& trusted, int& untrusted) = 0;
|
||||
virtual void getValidationTypes (uint256 const& ledger, int& full, int& partial) = 0;
|
||||
|
||||
virtual int getTrustedValidationCount (uint256 const& ledger) = 0;
|
||||
|
||||
virtual int getFeeAverage(uint256 const& ledger, uint64 ref, uint64& fee) = 0;
|
||||
|
||||
virtual int getNodesAfter (uint256 const& ledger) = 0;
|
||||
virtual int getLoadRatio (bool overLoaded) = 0;
|
||||
|
||||
// VFALCO TODO make a typedef for this ugly return value!
|
||||
virtual boost::unordered_map<uint256, currentValidationCount> getCurrentValidations (
|
||||
uint256 currentLedger, uint256 previousLedger) = 0;
|
||||
|
||||
virtual std::list <SerializedValidation::pointer> getCurrentTrustedValidations () = 0;
|
||||
|
||||
virtual void tune (int size, int age) = 0;
|
||||
|
||||
virtual void flush () = 0;
|
||||
|
||||
virtual void sweep () = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user