Tidy up TxFormat and create TxFormats, TxFlags

This commit is contained in:
Vinnie Falco
2013-06-15 07:18:14 -07:00
parent 17e370918b
commit 8aab3645cb
56 changed files with 1883 additions and 1599 deletions

View File

@@ -1,4 +1,27 @@
--------------------------------------------------------------------------------
TODO
--------------------------------------------------------------------------------
- Document in order:
SerializedType
STObject
SerializedLedgerEntry
- Replace uint160, uint256 in argument lists, template parameter lists, and
data members with tyepdefs from ripple_ProtocolTypes.h
--------------------------------------------------------------------------------
LoadEvent
Is referenced with both a shared pointer and an auto pointer.
JobQueue
getLoadEvent and getLoadEventAP differ only in the style of pointer
container which is returned. Unnecessary complexity.
--------------------------------------------------------------------------------
Naming
@@ -24,7 +47,7 @@ Verbose names
Ledger "Skip List"
Is not really a skip list
Is not really a skip list data structure
--------------------------------------------------------------------------------
@@ -42,10 +65,29 @@ Interfaces
would be more clear:
bool write (OutputStream& stream);
--------------------------------------------------------------------------------
Implementation
LoadManager
What is going on in the destructor
--------------------------------------------------------------------------------
boost
Unclear from the class declaration what style of shared object management
is used. Prefer to derive from a ReferenceCountedObject class so that the
behavior is explicit. Furthermore the use of intrusive containers is
preferred over the alternative.
make_shared <> () is awkward.
boost::recursive_mutex
Recursive mutexes should never be necessary.
They require the "mutable" keyword for const members to acquire the lock (yuck)
Replace recursive_mutex with juce::Mutex to remove boost dependency

View File

@@ -51,11 +51,11 @@
#include "src/cpp/ripple/TransactionMeta.h"
#include "src/cpp/ripple/Transaction.h"
#include "src/cpp/ripple/ripple_AccountState.h"
#include "src/cpp/ripple/NicknameState.h"
#include "src/cpp/ripple/ripple_NicknameState.h"
#include "src/cpp/ripple/Ledger.h"
#include "src/cpp/ripple/LedgerEntrySet.h"
#include "src/cpp/ripple/TransactionEngine.h"
#include "src/cpp/ripple/LoadManager.h"
#include "src/cpp/ripple/ripple_LoadManager.h"
#include "src/cpp/ripple/ripple_Peer.h"
#include "src/cpp/ripple/ripple_PeerSet.h"
#include "src/cpp/ripple/ripple_LedgerAcquire.h"

View File

@@ -0,0 +1,59 @@
#ifndef RIPPLE_HASHPREFIX_H
#define RIPPLE_HASHPREFIX_H
/** Prefix for hashing functions.
These prefixes are inserted before the source material used to
generate various hashes. This is done to put each hash in its own
"space." This way, two different types of objects with the
same binary data will produce different hashes.
Each prefix is a 4-byte value with the last byte set to zero
and the first three bytes formed from the ASCII equivalent of
some arbitrary string. For example "TXN".
@note Hash prefixes are part of the Ripple protocol.
@ingroup protocol
*/
struct HashPrefix
{
// VFALCO TODO Make these Doxygen comments and expand the
// description to complete, concise sentences.
//
// transaction plus signature to give transaction ID
static uint32 const transactionID = 0x54584E00; // 'TXN'
// transaction plus metadata
static uint32 const txNode = 0x534E4400; // 'TND'
// account state
static uint32 const leafNode = 0x4D4C4E00; // 'MLN'
// inner node in tree
static uint32 const innerNode = 0x4D494E00; // 'MIN'
// ledger master data for signing
static uint32 const ledgerMaster = 0x4C575200; // 'LGR'
// inner transaction to sign
static uint32 const txSign = 0x53545800; // 'STX'
// validation for signing
static uint32 const validation = 0x56414C00; // 'VAL'
// proposal for signing
static uint32 const proposal = 0x50525000; // 'PRP'
// inner transaction to sign (TESTNET)
static uint32 const txSignTestnet = 0x73747800; // 'stx'
// validation for signing (TESTNET)
static uint32 const validationTestnet = 0x76616C00; // 'val'
// proposal for signing (TESTNET)
static uint32 const proposalTestnet = 0x70727000; // 'prp'
};
#endif

View File

@@ -1,5 +1,26 @@
#ifndef RIPPLE_PROTOCOLTYPES_H
#define RIPPLE_PROTOCOLTYPES_H
#ifndef RIPPLE_PROTOCOL_H
#define RIPPLE_PROTOCOL_H
/** Protocol specific constants, types, and data.
This information is part of the Ripple protocol. Specifically,
it is required for peers to be able to communicate with each other.
@note Changing these will create a hard fork.
@ingroup protocol
@defgroup protocol
*/
struct Protocol
{
/** Smallest legal byte size of a transaction.
*/
static int const txMinSizeBytes = 32;
/** Largest legal byte size of a transaction.
*/
static int const txMaxSizeBytes = 1024 * 1024; // 1048576
};
/*
Hashes are used to uniquely identify objects like

View File

@@ -1262,12 +1262,12 @@ UPTR_T<STObject> STObject::parseJson (const Json::Value& object, SField::ref inN
{
if (field == sfTransactionType)
{
TransactionFormat* f = TransactionFormat::getTxnFormat (strValue);
TxFormat* f = TxFormats::getInstance ().findByName (strValue);
if (!f)
throw std::runtime_error ("Unknown transaction type");
data.push_back (new STUInt16 (field, static_cast<uint16> (f->t_type)));
data.push_back (new STUInt16 (field, static_cast<uint16> (f->getType ())));
if (*name == sfGeneric)
name = &sfTransaction;

View File

@@ -124,10 +124,10 @@ std::string STUInt16::getText () const
if (getFName () == sfTransactionType)
{
TransactionFormat* f = TransactionFormat::getTxnFormat (value);
TxFormat* f = TxFormats::getInstance ().findByType (static_cast <TransactionType> (value));
if (f != NULL)
return f->t_name;
return f->getName ();
}
return boost::lexical_cast<std::string> (value);
@@ -145,10 +145,10 @@ Json::Value STUInt16::getJson (int) const
if (getFName () == sfTransactionType)
{
TransactionFormat* f = TransactionFormat::getTxnFormat (value);
TxFormat* f = TxFormats::getInstance ().findByType (static_cast <TransactionType> (value));
if (f != NULL)
return f->t_name;
return f->getName ();
}
return value;

View File

@@ -11,6 +11,8 @@
// operator to copy the field name breaks the use of copy assignment just to copy values,
// which is used in the transaction engine code.
// VFALCO TODO Remove this unused enum
/*
enum PathFlags
{
PF_END = 0x00, // End of current path & path list.
@@ -24,6 +26,7 @@ enum PathFlags
PF_REDEEM = 0x40,
PF_ISSUE = 0x80,
};
*/
// VFALCO TODO make these non static or otherwise clean constants.
static const uint160 u160_zero (0), u160_one (1);
@@ -43,6 +46,9 @@ static inline const uint160& get_u160_one ()
#define ACCOUNT_XRP get_u160_zero()
#define ACCOUNT_ONE get_u160_one() // Used as a place holder.
// VFALCO TODO Document this as it looks like a central class.
// STObject is derived from it
//
class SerializedType
{
public:

View File

@@ -1,88 +0,0 @@
#ifndef RIPPLE_TRANSACTIONFORMAT_H
#define RIPPLE_TRANSACTIONFORMAT_H
enum TransactionType
{
ttINVALID = -1,
ttPAYMENT = 0,
ttCLAIM = 1, // open
ttWALLET_ADD = 2,
ttACCOUNT_SET = 3,
ttPASSWORD_FUND = 4, // open
ttREGULAR_KEY_SET = 5,
ttNICKNAME_SET = 6, // open
ttOFFER_CREATE = 7,
ttOFFER_CANCEL = 8,
ttCONTRACT = 9,
ttCONTRACT_REMOVE = 10, // can we use the same msg as offer cancel
ttTRUST_SET = 20,
ttFEATURE = 100,
ttFEE = 101,
};
class TransactionFormat
{
public:
std::string t_name;
TransactionType t_type;
SOTemplate elements;
static std::map<int, TransactionFormat*> byType;
static std::map<std::string, TransactionFormat*> byName;
TransactionFormat (const char* name, TransactionType type) : t_name (name), t_type (type)
{
byName[name] = this;
byType[type] = this;
}
TransactionFormat& operator<< (const SOElement& el)
{
elements.push_back (el);
return *this;
}
static TransactionFormat* getTxnFormat (TransactionType t);
static TransactionFormat* getTxnFormat (const std::string& t);
static TransactionFormat* getTxnFormat (int t);
};
const int TransactionMinLen = 32;
const int TransactionMaxLen = 1048576;
//
// Transaction flags.
//
// AccountSet flags:
const uint32 tfRequireDestTag = 0x00010000;
const uint32 tfOptionalDestTag = 0x00020000;
const uint32 tfRequireAuth = 0x00040000;
const uint32 tfOptionalAuth = 0x00080000;
const uint32 tfDisallowXRP = 0x00100000;
const uint32 tfAllowXRP = 0x00200000;
const uint32 tfAccountSetMask = ~ (tfRequireDestTag | tfOptionalDestTag
| tfRequireAuth | tfOptionalAuth
| tfDisallowXRP | tfAllowXRP);
// OfferCreate flags:
const uint32 tfPassive = 0x00010000;
const uint32 tfImmediateOrCancel = 0x00020000;
const uint32 tfFillOrKill = 0x00040000;
const uint32 tfSell = 0x00080000;
const uint32 tfOfferCreateMask = ~ (tfPassive | tfImmediateOrCancel | tfFillOrKill | tfSell);
// Payment flags:
const uint32 tfNoRippleDirect = 0x00010000;
const uint32 tfPartialPayment = 0x00020000;
const uint32 tfLimitQuality = 0x00040000;
const uint32 tfPaymentMask = ~ (tfPartialPayment | tfLimitQuality | tfNoRippleDirect);
// TrustSet flags:
const uint32 tfSetfAuth = 0x00010000;
const uint32 tfTrustSetMask = ~ (tfSetfAuth);
#endif
// vim:ts=4

View File

@@ -0,0 +1,51 @@
#ifndef RIPPLE_TXFLAGS_H
#define RIPPLE_TXFLAGS_H
//
// Transaction flags.
//
/** Transaction flags.
These flags modify the behavior of an operation.
@note Changing these will create a hard fork
@ingroup protocol
*/
class TxFlag
{
public:
static uint32 const requireDestTag = 0x00010000;
};
// VFALCO TODO Move all flags into this container after some study.
// AccountSet flags:
// VFALCO TODO Javadoc comment every one of these constants
//const uint32 TxFlag::requireDestTag = 0x00010000;
const uint32 tfOptionalDestTag = 0x00020000;
const uint32 tfRequireAuth = 0x00040000;
const uint32 tfOptionalAuth = 0x00080000;
const uint32 tfDisallowXRP = 0x00100000;
const uint32 tfAllowXRP = 0x00200000;
const uint32 tfAccountSetMask = ~ (TxFlag::requireDestTag | tfOptionalDestTag
| tfRequireAuth | tfOptionalAuth
| tfDisallowXRP | tfAllowXRP);
// OfferCreate flags:
const uint32 tfPassive = 0x00010000;
const uint32 tfImmediateOrCancel = 0x00020000;
const uint32 tfFillOrKill = 0x00040000;
const uint32 tfSell = 0x00080000;
const uint32 tfOfferCreateMask = ~ (tfPassive | tfImmediateOrCancel | tfFillOrKill | tfSell);
// Payment flags:
const uint32 tfNoRippleDirect = 0x00010000;
const uint32 tfPartialPayment = 0x00020000;
const uint32 tfLimitQuality = 0x00040000;
const uint32 tfPaymentMask = ~ (tfPartialPayment | tfLimitQuality | tfNoRippleDirect);
// TrustSet flags:
const uint32 tfSetfAuth = 0x00010000;
const uint32 tfTrustSetMask = ~ (tfSetfAuth);
#endif

View File

@@ -1,10 +1,7 @@
std::map<int, TransactionFormat*> TransactionFormat::byType;
// VFALCO TODO Find a way to not use macros. inline function?
std::map<std::string, TransactionFormat*> TransactionFormat::byName;
// VFALCO TODO surely we can think of a better way than to use macros??
#define TF_BASE \
#define TF_BASE \
<< SOElement(sfTransactionType, SOE_REQUIRED) \
<< SOElement(sfFlags, SOE_OPTIONAL) \
<< SOElement(sfSourceTag, SOE_OPTIONAL) \
@@ -16,11 +13,11 @@ std::map<std::string, TransactionFormat*> TransactionFormat::byName;
<< SOElement(sfSigningPubKey, SOE_REQUIRED) \
<< SOElement(sfTxnSignature, SOE_OPTIONAL)
#define DECLARE_TF(name, type) tf = new TransactionFormat(#name, type); (*tf) TF_BASE
#define DECLARE_TF(name, type) tf = TxFormats::getInstance().add (new TxFormat(#name, type)); (*tf) TF_BASE
void TFInit ()
{
TransactionFormat* tf;
TxFormat* tf;
DECLARE_TF (AccountSet, ttACCOUNT_SET)
<< SOElement (sfEmailHash, SOE_OPTIONAL)
@@ -86,35 +83,3 @@ void TFInit ()
<< SOElement (sfReserveIncrement, SOE_REQUIRED)
;
}
TransactionFormat* TransactionFormat::getTxnFormat (TransactionType t)
{
std::map<int, TransactionFormat*>::iterator it = byType.find (static_cast<int> (t));
if (it == byType.end ())
return NULL;
return it->second;
}
TransactionFormat* TransactionFormat::getTxnFormat (int t)
{
std::map<int, TransactionFormat*>::iterator it = byType.find ((t));
if (it == byType.end ())
return NULL;
return it->second;
}
TransactionFormat* TransactionFormat::getTxnFormat (const std::string& t)
{
std::map<std::string, TransactionFormat*>::iterator it = byName.find ((t));
if (it == byName.end ())
return NULL;
return it->second;
}
// vim:ts=4

View File

@@ -0,0 +1,70 @@
#ifndef RIPPLE_TXFORMAT_H
#define RIPPLE_TXFORMAT_H
// VFALCO TODO Rename to TxType
// Be aware there are some strings "TransactionType"
// And also we have TransactionType in ripple_SerializeDeclarations.h
//
/** Transaction type identifiers.
These are part of the binary message format.
@ingroup protocol
*/
enum TransactionType
{
ttINVALID = -1,
ttPAYMENT = 0,
ttCLAIM = 1, // open
ttWALLET_ADD = 2,
ttACCOUNT_SET = 3,
ttPASSWORD_FUND = 4, // open
ttREGULAR_KEY_SET = 5,
ttNICKNAME_SET = 6, // open
ttOFFER_CREATE = 7,
ttOFFER_CANCEL = 8,
ttCONTRACT = 9,
ttCONTRACT_REMOVE = 10, // can we use the same msg as offer cancel
ttTRUST_SET = 20,
ttFEATURE = 100,
ttFEE = 101,
};
class TxFormat
{
public:
TxFormat (char const* name, TransactionType type)
: m_name (name)
, m_type (type)
{
}
TxFormat& operator<< (SOElement const& el)
{
elements.push_back (el);
return *this;
}
/** Retrieve the name of the format.
*/
std::string const& getName () const { return m_name; }
/** Retrieve the transaction type this format represents.
*/
TransactionType getType () const { return m_type; }
public:
// VFALCO TODO make an accessor for this
SOTemplate elements;
private:
std::string const m_name;
TransactionType const m_type;
};
#endif
// vim:ts=4

View File

@@ -0,0 +1,49 @@
TxFormats& TxFormats::getInstance ()
{
static TxFormats instance;
return instance;
}
TxFormat* TxFormats::add (TxFormat* txFormat)
{
// VFALCO TODO Figure out when and how to delete the TxFormat objects later?
m_types [txFormat->getType ()] = txFormat;
m_names [txFormat->getName ()] = txFormat;
return txFormat;
}
TxFormat* TxFormats::findByType (TransactionType type)
{
TxFormat* result = NULL;
TypeMap::iterator const iter = m_types.find (type);
if (iter != m_types.end ())
{
result = iter->second;
}
return result;
}
TxFormat* TxFormats::findByName (std::string const& name)
{
TxFormat* result = NULL; // VFALCO TODO replace all NULL with nullptr
NameMap::iterator const iter = m_names.find (name);
if (iter != m_names.end ())
{
result = iter->second;
}
return result;
}
TxFormats::TxFormats ()
{
}

View File

@@ -0,0 +1,40 @@
#ifndef RIPPLE_TXFORMATS_H
#define RIPPLE_TXFORMATS_H
/** Manages the list of known transaction formats.
*/
class TxFormats
{
public:
// VFALCO TODO Make this a member of the Application object instead of a singleton?
static TxFormats& getInstance ();
/** Add a format.
The caller is responsible for freeing the memory.
@return The passed format.
*/
TxFormat* add (TxFormat* txFormat);
/** Retrieve a format based on its transaction type.
*/
TxFormat* findByType (TransactionType type);
/** Retrieve a format based on its name.
*/
TxFormat* findByName (std::string const& name);
private:
TxFormats ();
private:
typedef std::map <std::string, TxFormat*> NameMap;
typedef std::map <TransactionType, TxFormat*> TypeMap;
NameMap m_names;
TypeMap m_types;
};
#endif
// vim:ts=4

View File

@@ -85,7 +85,8 @@
#include "protocol/ripple_SerializedObjectTemplate.cpp"
#include "protocol/ripple_SerializedObject.cpp"
#include "protocol/ripple_TER.cpp"
#include "protocol/ripple_TransactionFormat.cpp"
#include "protocol/ripple_TxFormat.cpp"
#include "protocol/ripple_TxFormats.cpp"
// These are for STAmount
static const uint64 tenTo14 = 100000000000000ull;

View File

@@ -75,8 +75,9 @@
#include "crypto/ripple_Base58Data.h"
#include "protocol/ripple_FieldNames.h"
#include "protocol/ripple_HashPrefix.h"
#include "protocol/ripple_PackedMessage.h"
#include "protocol/ripple_ProtocolTypes.h"
#include "protocol/ripple_Protocol.h"
#include "protocol/ripple_RippleAddress.h"
#include "protocol/ripple_RippleSystem.h"
#include "protocol/ripple_Serializer.h" // needs CKey
@@ -85,7 +86,9 @@
#include "protocol/ripple_SerializedObjectTemplate.h"
#include "protocol/ripple_SerializedObject.h"
#include "protocol/ripple_LedgerFormat.h" // needs SOTemplate from SerializedObject
#include "protocol/ripple_TransactionFormat.h"
#include "protocol/ripple_TxFlags.h"
#include "protocol/ripple_TxFormat.h"
#include "protocol/ripple_TxFormats.h"
#include "utility/ripple_JSONCache.h"
#include "utility/ripple_UptimeTimerAdapter.h"

View File

@@ -128,11 +128,11 @@
#include "src/cpp/ripple/TransactionMeta.h"
#include "src/cpp/ripple/Transaction.h"
#include "src/cpp/ripple/ripple_AccountState.h"
#include "src/cpp/ripple/NicknameState.h"
#include "src/cpp/ripple/ripple_NicknameState.h"
#include "src/cpp/ripple/Ledger.h"
#include "src/cpp/ripple/SerializedValidation.h"
#include "src/cpp/ripple/LoadManager.h" // VFALCO TODO Split this file up
#include "src/cpp/ripple/ripple_LoadManager.h"
// These have few dependencies
@@ -218,19 +218,23 @@
#include "src/cpp/ripple/CallRPC.h"
#include "src/cpp/ripple/ChangeTransactor.h"
#include "src/cpp/ripple/HTTPRequest.h"
#include "src/cpp/ripple/HashPrefixes.h"
#include "src/cpp/ripple/HttpsClient.h"
#include "src/cpp/ripple/ripple_TransactionAcquire.h"
#include "src/cpp/ripple/ripple_DisputedTx.h"
#include "src/cpp/ripple/ripple_LedgerConsensus.h"
#include "src/cpp/ripple/LedgerTiming.h"
#include "src/cpp/ripple/Offer.h"
#include "src/cpp/ripple/ripple_Offer.h"
#include "src/cpp/ripple/OfferCancelTransactor.h"
#include "src/cpp/ripple/OfferCreateTransactor.h"
#include "src/cpp/ripple/ripple_PathRequest.h"
#include "src/cpp/ripple/ParameterTable.h"
#include "src/cpp/ripple/ParseSection.h"
#include "src/cpp/ripple/Pathfinder.h"
#include "src/cpp/ripple/ripple_RippleLineCache.h"
#include "src/cpp/ripple/ripple_PathState.h"
#include "src/cpp/ripple/ripple_RippleCalc.h"
#include "src/cpp/ripple/ripple_Pathfinder.h"
#include "src/cpp/ripple/PaymentTransactor.h"
#include "src/cpp/ripple/PeerDoor.h"
#include "src/cpp/ripple/RPC.h"
@@ -239,8 +243,7 @@
#include "src/cpp/ripple/RPCServer.h"
#include "src/cpp/ripple/RPCSub.h"
#include "src/cpp/ripple/RegularKeySetTransactor.h"
#include "src/cpp/ripple/RippleCalc.h"
#include "src/cpp/ripple/RippleState.h"
#include "src/cpp/ripple/ripple_RippleState.h"
#include "src/cpp/ripple/SerializedValidation.h"
#include "src/cpp/ripple/Transactor.h"
#include "src/cpp/ripple/AccountSetTransactor.h"
@@ -290,11 +293,11 @@ static const uint64 tenTo17m1 = tenTo17 - 1;
#include "src/cpp/ripple/LedgerMaster.cpp"
#include "src/cpp/ripple/LedgerProposal.cpp" // no log
#include "src/cpp/ripple/LedgerTiming.cpp"
#include "src/cpp/ripple/LoadManager.cpp"
#include "src/cpp/ripple/ripple_LoadManager.cpp"
#include "src/cpp/ripple/main.cpp"
#include "src/cpp/ripple/NetworkOPs.cpp"
#include "src/cpp/ripple/NicknameState.cpp" // no log
#include "src/cpp/ripple/Offer.cpp" // no log
#include "src/cpp/ripple/ripple_NicknameState.cpp"
#include "src/cpp/ripple/ripple_Offer.cpp" // no log
#include "src/cpp/ripple/OfferCancelTransactor.cpp"
#include "src/cpp/ripple/OfferCreateTransactor.cpp"
#include "src/cpp/ripple/Operation.cpp" // no log
@@ -316,12 +319,14 @@ static DH* handleTmpDh (SSL* ssl, int is_export, int iKeyLength)
#include "src/cpp/ripple/ParameterTable.cpp" // no log
#include "src/cpp/ripple/ParseSection.cpp"
#include "src/cpp/ripple/Pathfinder.cpp"
#include "src/cpp/ripple/ripple_Pathfinder.cpp"
#include "src/cpp/ripple/PaymentTransactor.cpp"
#include "src/cpp/ripple/PeerDoor.cpp"
#include "src/cpp/ripple/RegularKeySetTransactor.cpp"
#include "src/cpp/ripple/RippleCalc.cpp"
#include "src/cpp/ripple/RippleState.cpp" // no log
#include "src/cpp/ripple/ripple_PathState.cpp"
#include "src/cpp/ripple/ripple_RippleCalc.cpp"
#include "src/cpp/ripple/ripple_RippleLineCache.cpp"
#include "src/cpp/ripple/ripple_RippleState.cpp"
#include "src/cpp/ripple/rpc.cpp"
#include "src/cpp/ripple/RPCDoor.cpp"
#include "src/cpp/ripple/RPCErr.cpp"

View File

@@ -353,7 +353,13 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="modules\ripple_data\protocol\ripple_TransactionFormat.cpp">
<ClCompile Include="modules\ripple_data\protocol\ripple_TxFormat.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="modules\ripple_data\protocol\ripple_TxFormats.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
@@ -827,6 +833,12 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="src\cpp\ripple\ripple_PathState.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="src\cpp\ripple\ripple_Peers.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
@@ -909,7 +921,7 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="src\cpp\ripple\LoadManager.cpp">
<ClCompile Include="src\cpp\ripple\ripple_LoadManager.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
@@ -945,13 +957,13 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="src\cpp\ripple\NicknameState.cpp">
<ClCompile Include="src\cpp\ripple\ripple_NicknameState.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="src\cpp\ripple\Offer.cpp">
<ClCompile Include="src\cpp\ripple\ripple_Offer.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
@@ -999,7 +1011,7 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="src\cpp\ripple\Pathfinder.cpp">
<ClCompile Include="src\cpp\ripple\ripple_Pathfinder.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
@@ -1027,13 +1039,19 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="src\cpp\ripple\RippleCalc.cpp">
<ClCompile Include="src\cpp\ripple\ripple_RippleCalc.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="src\cpp\ripple\RippleState.cpp">
<ClCompile Include="src\cpp\ripple\ripple_RippleLineCache.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="src\cpp\ripple\ripple_RippleState.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
@@ -1393,9 +1411,10 @@
<ClInclude Include="modules\ripple_data\crypto\ripple_CKey.h" />
<ClInclude Include="modules\ripple_data\crypto\ripple_RFC1751.h" />
<ClInclude Include="modules\ripple_data\protocol\ripple_FieldNames.h" />
<ClInclude Include="modules\ripple_data\protocol\ripple_HashPrefix.h" />
<ClInclude Include="modules\ripple_data\protocol\ripple_LedgerFormat.h" />
<ClInclude Include="modules\ripple_data\protocol\ripple_PackedMessage.h" />
<ClInclude Include="modules\ripple_data\protocol\ripple_ProtocolTypes.h" />
<ClInclude Include="modules\ripple_data\protocol\ripple_Protocol.h" />
<ClInclude Include="modules\ripple_data\protocol\ripple_RippleAddress.h" />
<ClInclude Include="modules\ripple_data\protocol\ripple_RippleSystem.h" />
<ClInclude Include="modules\ripple_data\protocol\ripple_SerializeDeclarations.h" />
@@ -1404,7 +1423,9 @@
<ClInclude Include="modules\ripple_data\protocol\ripple_SerializedTypes.h" />
<ClInclude Include="modules\ripple_data\protocol\ripple_Serializer.h" />
<ClInclude Include="modules\ripple_data\protocol\ripple_TER.h" />
<ClInclude Include="modules\ripple_data\protocol\ripple_TransactionFormat.h" />
<ClInclude Include="modules\ripple_data\protocol\ripple_TxFlags.h" />
<ClInclude Include="modules\ripple_data\protocol\ripple_TxFormat.h" />
<ClInclude Include="modules\ripple_data\protocol\ripple_TxFormats.h" />
<ClInclude Include="modules\ripple_data\ripple_data.h" />
<ClInclude Include="modules\ripple_data\utility\ripple_JSONCache.h" />
<ClInclude Include="modules\ripple_data\utility\ripple_UptimeTimerAdapter.h" />
@@ -1751,7 +1772,6 @@
<ClInclude Include="src\cpp\ripple\ripple_InfoSub.h" />
<ClInclude Include="src\cpp\ripple\ripple_IPeers.h" />
<ClInclude Include="src\cpp\ripple\Contract.h" />
<ClInclude Include="src\cpp\ripple\HashPrefixes.h" />
<ClInclude Include="src\cpp\ripple\HTTPRequest.h" />
<ClInclude Include="src\cpp\ripple\HttpsClient.h" />
<ClInclude Include="src\cpp\ripple\Interpreter.h" />
@@ -1763,14 +1783,14 @@
<ClInclude Include="src\cpp\ripple\LedgerMaster.h" />
<ClInclude Include="src\cpp\ripple\LedgerProposal.h" />
<ClInclude Include="src\cpp\ripple\LedgerTiming.h" />
<ClInclude Include="src\cpp\ripple\LoadManager.h" />
<ClInclude Include="src\cpp\ripple\ripple_LoadManager.h" />
<ClInclude Include="src\cpp\ripple\ripple_Job.h" />
<ClInclude Include="src\cpp\ripple\ripple_JobQueue.h" />
<ClInclude Include="src\cpp\ripple\ripple_LedgerAcquireMaster.h" />
<ClInclude Include="src\cpp\ripple\ripple_LoadMonitor.h" />
<ClInclude Include="src\cpp\ripple\NetworkOPs.h" />
<ClInclude Include="src\cpp\ripple\NicknameState.h" />
<ClInclude Include="src\cpp\ripple\Offer.h" />
<ClInclude Include="src\cpp\ripple\ripple_NicknameState.h" />
<ClInclude Include="src\cpp\ripple\ripple_Offer.h" />
<ClInclude Include="src\cpp\ripple\OfferCancelTransactor.h" />
<ClInclude Include="src\cpp\ripple\OfferCreateTransactor.h" />
<ClInclude Include="src\cpp\ripple\Operation.h" />
@@ -1778,13 +1798,15 @@
<ClInclude Include="src\cpp\ripple\OrderBookDB.h" />
<ClInclude Include="src\cpp\ripple\ParameterTable.h" />
<ClInclude Include="src\cpp\ripple\ParseSection.h" />
<ClInclude Include="src\cpp\ripple\Pathfinder.h" />
<ClInclude Include="src\cpp\ripple\ripple_Pathfinder.h" />
<ClInclude Include="src\cpp\ripple\PaymentTransactor.h" />
<ClInclude Include="src\cpp\ripple\PeerDoor.h" />
<ClInclude Include="src\cpp\ripple\ripple_PathRequest.h" />
<ClInclude Include="src\cpp\ripple\RegularKeySetTransactor.h" />
<ClInclude Include="src\cpp\ripple\RippleCalc.h" />
<ClInclude Include="src\cpp\ripple\RippleState.h" />
<ClInclude Include="src\cpp\ripple\ripple_PathState.h" />
<ClInclude Include="src\cpp\ripple\ripple_RippleCalc.h" />
<ClInclude Include="src\cpp\ripple\ripple_RippleLineCache.h" />
<ClInclude Include="src\cpp\ripple\ripple_RippleState.h" />
<ClInclude Include="src\cpp\ripple\ripple_DatabaseCon.h" />
<ClInclude Include="src\cpp\ripple\ripple_IFeatures.h" />
<ClInclude Include="src\cpp\ripple\ripple_IFeeVote.h" />

View File

@@ -145,6 +145,9 @@
<Filter Include="1. Modules\ripple_main\refactored\consensus">
<UniqueIdentifier>{8b88138b-e5bd-492b-bd34-012b9f43e544}</UniqueIdentifier>
</Filter>
<Filter Include="1. Modules\ripple_main\refactored\pathing">
<UniqueIdentifier>{90a5527e-0de0-4d5f-a731-b6b196a013b5}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="src\cpp\database\sqlite3.c">
@@ -585,9 +588,6 @@
<ClCompile Include="modules\ripple_basics\utility\ripple_InstanceCounter.cpp">
<Filter>1. Modules\ripple_basics\utility</Filter>
</ClCompile>
<ClCompile Include="src\cpp\ripple\LoadManager.cpp">
<Filter>1. Modules\ripple_main\_unfactored\main</Filter>
</ClCompile>
<ClCompile Include="src\cpp\ripple\main.cpp">
<Filter>1. Modules\ripple_main\_unfactored\main</Filter>
</ClCompile>
@@ -651,24 +651,9 @@
<ClCompile Include="src\cpp\ripple\LedgerTiming.cpp">
<Filter>1. Modules\ripple_main\_unfactored\ledger</Filter>
</ClCompile>
<ClCompile Include="src\cpp\ripple\NicknameState.cpp">
<Filter>1. Modules\ripple_main\_unfactored\ledger</Filter>
</ClCompile>
<ClCompile Include="src\cpp\ripple\Offer.cpp">
<Filter>1. Modules\ripple_main\_unfactored\ledger</Filter>
</ClCompile>
<ClCompile Include="src\cpp\ripple\OrderBookDB.cpp">
<Filter>1. Modules\ripple_main\_unfactored\ledger</Filter>
</ClCompile>
<ClCompile Include="src\cpp\ripple\Pathfinder.cpp">
<Filter>1. Modules\ripple_main\_unfactored\ledger</Filter>
</ClCompile>
<ClCompile Include="src\cpp\ripple\RippleCalc.cpp">
<Filter>1. Modules\ripple_main\_unfactored\ledger</Filter>
</ClCompile>
<ClCompile Include="src\cpp\ripple\RippleState.cpp">
<Filter>1. Modules\ripple_main\_unfactored\ledger</Filter>
</ClCompile>
<ClCompile Include="modules\ripple_data\crypto\ripple_CKeyDeterministic.cpp">
<Filter>1. Modules\ripple_data\crypto</Filter>
</ClCompile>
@@ -732,9 +717,6 @@
<ClCompile Include="modules\ripple_data\protocol\ripple_TER.cpp">
<Filter>1. Modules\ripple_data\protocol</Filter>
</ClCompile>
<ClCompile Include="modules\ripple_data\protocol\ripple_TransactionFormat.cpp">
<Filter>1. Modules\ripple_data\protocol</Filter>
</ClCompile>
<ClCompile Include="modules\ripple_data\protocol\ripple_STAmount.cpp">
<Filter>1. Modules\ripple_data\protocol</Filter>
</ClCompile>
@@ -798,12 +780,6 @@
<ClCompile Include="src\cpp\ripple\ripple_AcceptedLedger.cpp">
<Filter>1. Modules\ripple_main\refactored</Filter>
</ClCompile>
<ClCompile Include="src\cpp\ripple\ripple_PathRequest.cpp">
<Filter>1. Modules\ripple_main\_unfactored\ledger</Filter>
</ClCompile>
<ClCompile Include="src\cpp\ripple\ripple_Application.cpp">
<Filter>1. Modules\ripple_main\_unfactored\main</Filter>
</ClCompile>
<ClCompile Include="modules\ripple_data\utility\ripple_JSONCache.cpp">
<Filter>1. Modules\ripple_data\utility</Filter>
</ClCompile>
@@ -876,6 +852,42 @@
<ClCompile Include="src\cpp\ripple\ripple_LedgerConsensus.cpp">
<Filter>1. Modules\ripple_main\refactored\consensus</Filter>
</ClCompile>
<ClCompile Include="src\cpp\ripple\ripple_Offer.cpp">
<Filter>1. Modules\ripple_main\refactored</Filter>
</ClCompile>
<ClCompile Include="src\cpp\ripple\ripple_NicknameState.cpp">
<Filter>1. Modules\ripple_main\refactored</Filter>
</ClCompile>
<ClCompile Include="src\cpp\ripple\ripple_LoadManager.cpp">
<Filter>1. Modules\ripple_main\refactored</Filter>
</ClCompile>
<ClCompile Include="src\cpp\ripple\ripple_Application.cpp">
<Filter>1. Modules\ripple_main\refactored</Filter>
</ClCompile>
<ClCompile Include="src\cpp\ripple\ripple_PathRequest.cpp">
<Filter>1. Modules\ripple_main\refactored\pathing</Filter>
</ClCompile>
<ClCompile Include="src\cpp\ripple\ripple_Pathfinder.cpp">
<Filter>1. Modules\ripple_main\refactored\pathing</Filter>
</ClCompile>
<ClCompile Include="src\cpp\ripple\ripple_RippleState.cpp">
<Filter>1. Modules\ripple_main\refactored\pathing</Filter>
</ClCompile>
<ClCompile Include="src\cpp\ripple\ripple_RippleLineCache.cpp">
<Filter>1. Modules\ripple_main\refactored\pathing</Filter>
</ClCompile>
<ClCompile Include="src\cpp\ripple\ripple_PathState.cpp">
<Filter>1. Modules\ripple_main\refactored\pathing</Filter>
</ClCompile>
<ClCompile Include="src\cpp\ripple\ripple_RippleCalc.cpp">
<Filter>1. Modules\ripple_main\refactored\pathing</Filter>
</ClCompile>
<ClCompile Include="modules\ripple_data\protocol\ripple_TxFormat.cpp">
<Filter>1. Modules\ripple_data\protocol</Filter>
</ClCompile>
<ClCompile Include="modules\ripple_data\protocol\ripple_TxFormats.cpp">
<Filter>1. Modules\ripple_data\protocol</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="database\sqlite3ext.h">
@@ -1193,9 +1205,6 @@
<ClInclude Include="src\cpp\ripple\Contract.h">
<Filter>1. Modules\ripple_main\_unfactored\contracts</Filter>
</ClInclude>
<ClInclude Include="src\cpp\ripple\HashPrefixes.h">
<Filter>1. Modules\ripple_main\_unfactored\types</Filter>
</ClInclude>
<ClInclude Include="src\cpp\ripple\ParameterTable.h">
<Filter>1. Modules\ripple_main\_unfactored\types</Filter>
</ClInclude>
@@ -1349,9 +1358,6 @@
<ClInclude Include="modules\ripple_basics\utility\ripple_InstanceCounter.h">
<Filter>1. Modules\ripple_basics\utility</Filter>
</ClInclude>
<ClInclude Include="src\cpp\ripple\LoadManager.h">
<Filter>1. Modules\ripple_main\_unfactored\main</Filter>
</ClInclude>
<ClInclude Include="src\cpp\ripple\Version.h">
<Filter>1. Modules\ripple_main\_unfactored\main</Filter>
</ClInclude>
@@ -1415,24 +1421,9 @@
<ClInclude Include="src\cpp\ripple\LedgerTiming.h">
<Filter>1. Modules\ripple_main\_unfactored\ledger</Filter>
</ClInclude>
<ClInclude Include="src\cpp\ripple\NicknameState.h">
<Filter>1. Modules\ripple_main\_unfactored\ledger</Filter>
</ClInclude>
<ClInclude Include="src\cpp\ripple\Offer.h">
<Filter>1. Modules\ripple_main\_unfactored\ledger</Filter>
</ClInclude>
<ClInclude Include="src\cpp\ripple\OrderBookDB.h">
<Filter>1. Modules\ripple_main\_unfactored\ledger</Filter>
</ClInclude>
<ClInclude Include="src\cpp\ripple\Pathfinder.h">
<Filter>1. Modules\ripple_main\_unfactored\ledger</Filter>
</ClInclude>
<ClInclude Include="src\cpp\ripple\RippleCalc.h">
<Filter>1. Modules\ripple_main\_unfactored\ledger</Filter>
</ClInclude>
<ClInclude Include="src\cpp\ripple\RippleState.h">
<Filter>1. Modules\ripple_main\_unfactored\ledger</Filter>
</ClInclude>
<ClInclude Include="src\cpp\ripple\SerializedValidation.h">
<Filter>1. Modules\ripple_main\_unfactored\ledger</Filter>
</ClInclude>
@@ -1499,9 +1490,6 @@
<ClInclude Include="modules\ripple_data\protocol\ripple_TER.h">
<Filter>1. Modules\ripple_data\protocol</Filter>
</ClInclude>
<ClInclude Include="modules\ripple_data\protocol\ripple_TransactionFormat.h">
<Filter>1. Modules\ripple_data\protocol</Filter>
</ClInclude>
<ClInclude Include="modules\ripple_data\protocol\ripple_RippleSystem.h">
<Filter>1. Modules\ripple_data\protocol</Filter>
</ClInclude>
@@ -1544,9 +1532,6 @@
<ClInclude Include="modules\ripple_basics\types\ripple_BasicTypes.h">
<Filter>1. Modules\ripple_basics\types</Filter>
</ClInclude>
<ClInclude Include="modules\ripple_data\protocol\ripple_ProtocolTypes.h">
<Filter>1. Modules\ripple_data\protocol</Filter>
</ClInclude>
<ClInclude Include="src\cpp\ripple\ripple_LedgerAcquire.h">
<Filter>1. Modules\ripple_main\refactored</Filter>
</ClInclude>
@@ -1568,12 +1553,6 @@
<ClInclude Include="src\cpp\ripple\ripple_AcceptedLedger.h">
<Filter>1. Modules\ripple_main\refactored</Filter>
</ClInclude>
<ClInclude Include="src\cpp\ripple\ripple_PathRequest.h">
<Filter>1. Modules\ripple_main\_unfactored\ledger</Filter>
</ClInclude>
<ClInclude Include="src\cpp\ripple\ripple_IApplication.h">
<Filter>1. Modules\ripple_main\_unfactored\main</Filter>
</ClInclude>
<ClInclude Include="modules\ripple_data\utility\ripple_UptimeTimerAdapter.h">
<Filter>1. Modules\ripple_data\utility</Filter>
</ClInclude>
@@ -1631,6 +1610,51 @@
<ClInclude Include="src\cpp\ripple\ripple_LedgerConsensus.h">
<Filter>1. Modules\ripple_main\refactored\consensus</Filter>
</ClInclude>
<ClInclude Include="src\cpp\ripple\ripple_Offer.h">
<Filter>1. Modules\ripple_main\refactored</Filter>
</ClInclude>
<ClInclude Include="src\cpp\ripple\ripple_NicknameState.h">
<Filter>1. Modules\ripple_main\refactored</Filter>
</ClInclude>
<ClInclude Include="src\cpp\ripple\ripple_LoadManager.h">
<Filter>1. Modules\ripple_main\refactored</Filter>
</ClInclude>
<ClInclude Include="src\cpp\ripple\ripple_IApplication.h">
<Filter>1. Modules\ripple_main\refactored</Filter>
</ClInclude>
<ClInclude Include="src\cpp\ripple\ripple_PathRequest.h">
<Filter>1. Modules\ripple_main\refactored\pathing</Filter>
</ClInclude>
<ClInclude Include="src\cpp\ripple\ripple_Pathfinder.h">
<Filter>1. Modules\ripple_main\refactored\pathing</Filter>
</ClInclude>
<ClInclude Include="src\cpp\ripple\ripple_RippleState.h">
<Filter>1. Modules\ripple_main\refactored\pathing</Filter>
</ClInclude>
<ClInclude Include="src\cpp\ripple\ripple_RippleLineCache.h">
<Filter>1. Modules\ripple_main\refactored\pathing</Filter>
</ClInclude>
<ClInclude Include="src\cpp\ripple\ripple_PathState.h">
<Filter>1. Modules\ripple_main\refactored\pathing</Filter>
</ClInclude>
<ClInclude Include="src\cpp\ripple\ripple_RippleCalc.h">
<Filter>1. Modules\ripple_main\refactored\pathing</Filter>
</ClInclude>
<ClInclude Include="modules\ripple_data\protocol\ripple_HashPrefix.h">
<Filter>1. Modules\ripple_data\protocol</Filter>
</ClInclude>
<ClInclude Include="modules\ripple_data\protocol\ripple_TxFormat.h">
<Filter>1. Modules\ripple_data\protocol</Filter>
</ClInclude>
<ClInclude Include="modules\ripple_data\protocol\ripple_Protocol.h">
<Filter>1. Modules\ripple_data\protocol</Filter>
</ClInclude>
<ClInclude Include="modules\ripple_data\protocol\ripple_TxFlags.h">
<Filter>1. Modules\ripple_data\protocol</Filter>
</ClInclude>
<ClInclude Include="modules\ripple_data\protocol\ripple_TxFormats.h">
<Filter>1. Modules\ripple_data\protocol</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="SConstruct" />

View File

@@ -52,14 +52,15 @@ TER AccountSetTransactor::doApply ()
// RequireDestTag
//
if ((tfRequireDestTag | tfOptionalDestTag) == (uTxFlags & (tfRequireDestTag | tfOptionalDestTag)))
// VFALCO TODO Make a function bool areBothFlagsSet (uint value, uint flag1, uint flag2)
if ((TxFlag::requireDestTag | tfOptionalDestTag) == (uTxFlags & (TxFlag::requireDestTag | tfOptionalDestTag)))
{
WriteLog (lsINFO, AccountSetTransactor) << "AccountSet: Malformed transaction: Contradictory flags set.";
return temINVALID_FLAG;
}
if ((uTxFlags & tfRequireDestTag) && !isSetBit (uFlagsIn, lsfRequireDestTag))
if ((uTxFlags & TxFlag::requireDestTag) && !isSetBit (uFlagsIn, lsfRequireDestTag))
{
WriteLog (lsINFO, AccountSetTransactor) << "AccountSet: Set lsfRequireDestTag.";

View File

@@ -1,40 +0,0 @@
#ifndef __HASHPREFIXES__
#define __HASHPREFIXES__
// TXN - Hash of transaction plus signature to give transaction ID
const uint32 sHP_TransactionID = 0x54584E00;
// TND - Hash of transaction plus metadata
const uint32 sHP_TransactionNode = 0x534E4400;
// MLN - Hash of account state
const uint32 sHP_LeafNode = 0x4D4C4E00;
// MIN - Hash of inner node in tree
const uint32 sHP_InnerNode = 0x4D494E00;
// LGR - Hash of ledger master data for signing
const uint32 sHP_Ledger = 0x4C575200;
// STX - Hash of inner transaction to sign
const uint32 sHP_TransactionSign = 0x53545800;
// VAL - Hash of validation for signing
const uint32 sHP_Validation = 0x56414C00;
// PRP - Hash of proposal for signing
const uint32 sHP_Proposal = 0x50525000;
// stx - TESTNET Hash of inner transaction to sign
const uint32 sHP_TestNetTransactionSign = 0x73747800;
// val - TESTNET Hash of validation for signing
const uint32 sHP_TestNetValidation = 0x76616C00;
// prp - TESTNET Hash of proposal for signing
const uint32 sHP_TestNetProposal = 0x70727000;
#endif
// vim:ts=4

View File

@@ -192,7 +192,7 @@ void Ledger::updateHash ()
}
Serializer s (118);
s.add32 (sHP_Ledger);
s.add32 (HashPrefix::ledgerMaster);
addRaw (s);
mHash = s.getSHA512Half ();
mValidHash = true;
@@ -526,7 +526,7 @@ void Ledger::saveAcceptedLedger (Job&, bool fromConsensus)
// Save the ledger header in the hashed object store
Serializer s (128);
s.add32 (sHP_Ledger);
s.add32 (HashPrefix::ledgerMaster);
addRaw (s);
theApp->getHashedObjectStore ().store (hotLEDGER, mLedgerSeq, s.peekData (), mHash);

View File

@@ -2172,7 +2172,7 @@ void NetworkOPs::makeFetchPack (Job&, boost::weak_ptr<Peer> wPeer,
ripple::TMIndexedObject& newObj = *reply.add_objects ();
newObj.set_hash (wantLedger->getHash ().begin (), 256 / 8);
Serializer s (256);
s.add32 (sHP_Ledger);
s.add32 (HashPrefix::ledgerMaster);
wantLedger->addRaw (s);
newObj.set_data (s.getDataPtr (), s.getLength ());
newObj.set_ledgerseq (lSeq);

View File

@@ -2,15 +2,6 @@
// Carries out the RPC.
//
#include "Pathfinder.h"
#include "RPCHandler.h"
#include "RPCSub.h"
#include "Wallet.h"
#include "RippleCalc.h"
#include "RPCErr.h"
#include "NicknameState.h"
#include "Offer.h"
SETUP_LOG (RPCHandler)
static const int rpcCOST_DEFAULT = 10;
@@ -182,7 +173,7 @@ Json::Value RPCHandler::transactionSign (Json::Value jvRequest, bool bSubmit, Sc
Ledger::pointer lSnapshot = mNetOps->getCurrentSnapshot ();
{
bool bValid;
RLCache::pointer cache = boost::make_shared<RLCache> (lSnapshot);
RippleLineCache::pointer cache = boost::make_shared<RippleLineCache> (lSnapshot);
Pathfinder pf (cache, raSrcAddressID, dstAccountID,
saSendMax.getCurrency (), saSendMax.getIssuer (), saSend, bValid);
@@ -1517,7 +1508,7 @@ Json::Value RPCHandler::doRipplePathFind (Json::Value jvRequest, int& cost, Scop
jvResult["destination_account"] = raDst.humanAccountID ();
Json::Value jvArray (Json::arrayValue);
RLCache::pointer cache = boost::make_shared<RLCache> (lSnapShot);
RippleLineCache::pointer cache = boost::make_shared<RippleLineCache> (lSnapShot);
for (unsigned int i = 0; i != jvSrcCurrencies.size (); ++i)
{

View File

@@ -3,7 +3,6 @@
#include "HTTPRequest.h"
#include "RPCHandler.h"
#include "LoadManager.h"
class RPCServer : public boost::enable_shared_from_this<RPCServer>
{

View File

@@ -1,236 +0,0 @@
#ifndef __RIPPLE_CALC__
#define __RIPPLE_CALC__
#include <boost/unordered_set.hpp>
#include <boost/tuple/tuple.hpp>
#include "LedgerEntrySet.h"
// VFALCO TODO move this to a separate file
class PaymentNode
{
public:
bool operator== (const PaymentNode& pnOther) const;
Json::Value getJson () const;
private:
// VFALCO TODO remove the need for friend declaration
friend class RippleCalc;
friend class PathState;
uint16 uFlags; // --> From path.
uint160 uAccountID; // --> Accounts: Recieving/sending account.
uint160 uCurrencyID; // --> Accounts: Receive and send, Offers: send.
// --- For offer's next has currency out.
uint160 uIssuerID; // --> Currency's issuer
STAmount saTransferRate; // Transfer rate for uIssuerID.
// Computed by Reverse.
STAmount saRevRedeem; // <-- Amount to redeem to next.
STAmount saRevIssue; // <-- Amount to issue to next limited by credit and outstanding IOUs.
// Issue isn't used by offers.
STAmount saRevDeliver; // <-- Amount to deliver to next regardless of fee.
// Computed by forward.
STAmount saFwdRedeem; // <-- Amount node will redeem to next.
STAmount saFwdIssue; // <-- Amount node will issue to next.
// Issue isn't used by offers.
STAmount saFwdDeliver; // <-- Amount to deliver to next regardless of fee.
// For offers:
STAmount saRateMax;
// Directory
uint256 uDirectTip; // Current directory.
uint256 uDirectEnd; // Next order book.
bool bDirectAdvance; // Need to advance directory.
SLE::pointer sleDirectDir;
STAmount saOfrRate; // For correct ratio.
// Node
bool bEntryAdvance; // Need to advance entry.
unsigned int uEntry;
uint256 uOfferIndex;
SLE::pointer sleOffer;
uint160 uOfrOwnerID;
bool bFundsDirty; // Need to refresh saOfferFunds, saTakerPays, & saTakerGets.
STAmount saOfferFunds;
STAmount saTakerPays;
STAmount saTakerGets;
};
// account id, currency id, issuer id :: node
typedef boost::tuple<uint160, uint160, uint160> aciSource;
typedef boost::unordered_map<aciSource, unsigned int> curIssuerNode; // Map of currency, issuer to node index.
typedef boost::unordered_map<aciSource, unsigned int>::const_iterator curIssuerNodeConstIterator;
extern std::size_t hash_value (const aciSource& asValue);
// Holds a path state under incremental application.
class PathState
{
public:
typedef boost::shared_ptr<PathState> pointer;
typedef const boost::shared_ptr<PathState>& ref;
TER terStatus;
std::vector<PaymentNode> vpnNodes;
// When processing, don't want to complicate directory walking with deletion.
std::vector<uint256> vUnfundedBecame; // Offers that became unfunded or were completely consumed.
// First time scanning foward, as part of path contruction, a funding source was mentioned for accounts. Source may only be
// used there.
curIssuerNode umForward; // Map of currency, issuer to node index.
// First time working in reverse a funding source was used.
// Source may only be used there if not mentioned by an account.
curIssuerNode umReverse; // Map of currency, issuer to node index.
LedgerEntrySet lesEntries;
int mIndex; // Index/rank amoung siblings.
uint64 uQuality; // 0 = no quality/liquity left.
const STAmount& saInReq; // --> Max amount to spend by sender.
STAmount saInAct; // --> Amount spent by sender so far.
STAmount saInPass; // <-- Amount spent by sender.
const STAmount& saOutReq; // --> Amount to send.
STAmount saOutAct; // --> Amount actually sent so far.
STAmount saOutPass; // <-- Amount actually sent.
bool bConsumed; // If true, use consumes full liquidity. False, may or may not.
PathState* setIndex (const int iIndex)
{
mIndex = iIndex;
return this;
}
int getIndex ()
{
return mIndex;
};
PathState (
const STAmount& saSend,
const STAmount& saSendMax
) : saInReq (saSendMax), saOutReq (saSend)
{
;
}
PathState (const PathState& psSrc, bool bUnused)
: saInReq (psSrc.saInReq), saOutReq (psSrc.saOutReq)
{
;
}
void setExpanded (
const LedgerEntrySet& lesSource,
const STPath& spSourcePath,
const uint160& uReceiverID,
const uint160& uSenderID
);
void setCanonical (
const PathState& psExpanded
);
Json::Value getJson () const;
#if 0
static PathState::pointer createCanonical (
PathState& ref pspExpanded
)
{
PathState::pointer pspNew = boost::make_shared<PathState> (pspExpanded->saOutAct, pspExpanded->saInAct);
pspNew->setCanonical (pspExpanded);
return pspNew;
}
#endif
static bool lessPriority (PathState& lhs, PathState& rhs);
private:
TER pushNode (const int iType, const uint160& uAccountID, const uint160& uCurrencyID, const uint160& uIssuerID);
TER pushImply (const uint160& uAccountID, const uint160& uCurrencyID, const uint160& uIssuerID);
};
class RippleCalc
{
public:
// First time working in reverse a funding source was mentioned. Source may only be used there.
curIssuerNode mumSource; // Map of currency, issuer to node index.
// If the transaction fails to meet some constraint, still need to delete unfunded offers.
boost::unordered_set<uint256> musUnfundedFound; // Offers that were found unfunded.
void pathNext (PathState::ref psrCur, const bool bMultiQuality, const LedgerEntrySet& lesCheckpoint, LedgerEntrySet& lesCurrent);
TER calcNode (const unsigned int uNode, PathState& psCur, const bool bMultiQuality);
TER calcNodeRev (const unsigned int uNode, PathState& psCur, const bool bMultiQuality);
TER calcNodeFwd (const unsigned int uNode, PathState& psCur, const bool bMultiQuality);
TER calcNodeOfferRev (const unsigned int uNode, PathState& psCur, const bool bMultiQuality);
TER calcNodeOfferFwd (const unsigned int uNode, PathState& psCur, const bool bMultiQuality);
TER calcNodeAccountRev (const unsigned int uNode, PathState& psCur, const bool bMultiQuality);
TER calcNodeAccountFwd (const unsigned int uNode, PathState& psCur, const bool bMultiQuality);
TER calcNodeAdvance (const unsigned int uNode, PathState& psCur, const bool bMultiQuality, const bool bReverse);
TER calcNodeDeliverRev (
const unsigned int uNode,
PathState& psCur,
const bool bMultiQuality,
const uint160& uOutAccountID,
const STAmount& saOutReq,
STAmount& saOutAct);
TER calcNodeDeliverFwd (
const unsigned int uNode,
PathState& psCur,
const bool bMultiQuality,
const uint160& uInAccountID,
const STAmount& saInReq,
STAmount& saInAct,
STAmount& saInFees);
void calcNodeRipple (const uint32 uQualityIn, const uint32 uQualityOut,
const STAmount& saPrvReq, const STAmount& saCurReq,
STAmount& saPrvAct, STAmount& saCurAct,
uint64& uRateMax);
RippleCalc (LedgerEntrySet& lesNodes, const bool bOpenLedger)
: lesActive (lesNodes), mOpenLedger (bOpenLedger)
{
;
}
static TER rippleCalc (
LedgerEntrySet& lesActive,
STAmount& saMaxAmountAct,
STAmount& saDstAmountAct,
std::vector<PathState::pointer>& vpsExpanded,
const STAmount& saDstAmountReq,
const STAmount& saMaxAmountReq,
const uint160& uDstAccountID,
const uint160& uSrcAccountID,
const STPathSet& spsPaths,
const bool bPartialPayment,
const bool bLimitQuality,
const bool bNoRippleDirect,
const bool bStandAlone, // --> True, not to affect accounts.
const bool bOpenLedger = true // --> What kind of errors to return.
);
static void setCanonical (STPathSet& spsDst, const std::vector<PathState::pointer>& vpsExpanded, bool bKeepDefault);
protected:
LedgerEntrySet& lesActive;
bool mOpenLedger;
};
#endif
// vim:ts=4

View File

@@ -35,8 +35,10 @@ public:
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 ()

View File

@@ -1,8 +1,7 @@
// VFALCO TODO Wrap this up in something neater. Replace NULL with nullptr
IApplication* theApp = NULL;
class Application;
SETUP_LOG (Application)

View File

@@ -101,9 +101,18 @@ void Config::setup (const std::string& strConf, bool bTestNet, bool bQuiet)
% VALIDATORS_FILE_NAME);
VALIDATORS_URI = boost::str (boost::format ("/%s") % VALIDATORS_BASE);
SIGN_TRANSACTION = TESTNET ? sHP_TestNetTransactionSign : sHP_TransactionSign;
SIGN_VALIDATION = TESTNET ? sHP_TestNetValidation : sHP_Validation;
SIGN_PROPOSAL = TESTNET ? sHP_TestNetProposal : sHP_Proposal;
if (TESTNET)
{
SIGN_TRANSACTION = HashPrefix::txSignTestnet;
SIGN_VALIDATION = HashPrefix::validationTestnet;
SIGN_PROPOSAL = HashPrefix::proposalTestnet;
}
else
{
SIGN_TRANSACTION = HashPrefix::txSign;
SIGN_VALIDATION = HashPrefix::validation;
SIGN_PROPOSAL = HashPrefix::proposal;
}
if (TESTNET)
Base58::setCurrentAlphabet (Base58::getTestnetAlphabet ());

View File

@@ -108,4 +108,3 @@ public:
extern IApplication* theApp;
#endif
// vim:ts=4

View File

@@ -16,11 +16,17 @@ public:
void shutdown ();
void setThreadCount (int c = 0);
// VFALCO TODO Rename these to newLoadEventMeasurement or something similar
// since they create the object.
//
LoadEvent::pointer getLoadEvent (JobType t, const std::string& name)
{
return boost::make_shared<LoadEvent> (boost::ref (mJobLoads[t]), name, true);
}
// VFALCO TODO Why do we need two versions, one which returns a shared
// pointer and the other which returns an autoptr?
//
LoadEvent::autoptr getLoadEventAP (JobType t, const std::string& name)
{
return LoadEvent::autoptr (new LoadEvent (mJobLoads[t], name, true));

View File

@@ -643,7 +643,7 @@ bool LedgerAcquire::takeBase (const std::string& data) // data must not have has
mHaveBase = true;
Serializer s (data.size () + 4);
s.add32 (sHP_Ledger);
s.add32 (HashPrefix::ledgerMaster);
s.addRaw (data);
theApp->getHashedObjectStore ().store (hotLEDGER, mLedger->getLedgerSeq (), s.peekData (), mHash);

View File

@@ -3,14 +3,25 @@
class LoadMonitor;
// VFALCO NOTE What is the difference between a LoadEvent and a LoadMonitor?
// VFALCO TODO Rename LoadEvent to LoadMonitor::Event
//
// This looks like a scoped elapsed time measuring class
//
class LoadEvent
{
public:
typedef boost::shared_ptr<LoadEvent> pointer;
typedef UPTR_T<LoadEvent> autoptr;
// VFALCO NOTE Why are these shared pointers? Wouldn't there be a
// piece of lifetime-managed calling code that can simply own
// the object?
//
// Why both kinds of containers?
//
typedef boost::shared_ptr <LoadEvent> pointer;
typedef UPTR_T <LoadEvent> autoptr;
public:
// VFALCO TODO remove the dependency on LoadMonitor.
// VFALCO TODO remove the dependency on LoadMonitor. Is that possible?
LoadEvent (LoadMonitor& monitor,
const std::string& name,
bool shouldStart);

View File

@@ -11,19 +11,18 @@ LoadManager::LoadManager (int creditRate, int creditLimit, int debitWarn, int de
, mDeadLock (0)
, mCosts (LT_MAX)
{
addLoadCost (LoadCost (LT_InvalidRequest, -10, LC_CPU | LC_Network));
addLoadCost (LoadCost (LT_RequestNoReply, -1, LC_CPU | LC_Disk));
addLoadCost (LoadCost (LT_InvalidSignature, -100, LC_CPU));
addLoadCost (LoadCost (LT_UnwantedData, -5, LC_CPU | LC_Network));
addLoadCost (LoadCost (LT_BadData, -20, LC_CPU));
addCost (Cost (LT_InvalidRequest, -10, LC_CPU | LC_Network));
addCost (Cost (LT_RequestNoReply, -1, LC_CPU | LC_Disk));
addCost (Cost (LT_InvalidSignature, -100, LC_CPU));
addCost (Cost (LT_UnwantedData, -5, LC_CPU | LC_Network));
addCost (Cost (LT_BadData, -20, LC_CPU));
addLoadCost (LoadCost (LT_NewTrusted, -10, 0));
addLoadCost (LoadCost (LT_NewTransaction, -2, 0));
addLoadCost (LoadCost (LT_NeededData, -10, 0));
addLoadCost (LoadCost (LT_RequestData, -5, LC_Disk | LC_Network));
addLoadCost (LoadCost (LT_CheapQuery, -1, LC_CPU));
addCost (Cost (LT_NewTrusted, -10, 0));
addCost (Cost (LT_NewTransaction, -2, 0));
addCost (Cost (LT_NeededData, -10, 0));
addCost (Cost (LT_RequestData, -5, LC_Disk | LC_Network));
addCost (Cost (LT_CheapQuery, -1, LC_CPU));
}
void LoadManager::init ()
@@ -164,7 +163,7 @@ bool LoadManager::shouldCutoff (LoadSource& source) const
bool LoadManager::adjust (LoadSource& source, LoadType t) const
{
// FIXME: Scale by category
LoadCost cost = mCosts[static_cast<int> (t)];
Cost cost = mCosts[static_cast<int> (t)];
return adjust (source, cost.mCost);
}

View File

@@ -26,25 +26,12 @@ enum LoadType
};
// load categories
static const int LC_Disk = 1;
static const int LC_CPU = 2;
static const int LC_Network = 4;
class LoadCost
// VFALCO NOTE These look like bit flags, name them accordingly
enum
{
public:
LoadType mType;
int mCost;
int mCategories;
LoadCost () : mType (), mCost (0), mCategories (0)
{
;
}
LoadCost (LoadType t, int cost, int cat) : mType (t), mCost (cost), mCategories (cat)
{
;
}
LC_Disk = 1,
LC_CPU = 2,
LC_Network = 4
};
// a single endpoint that can impose load
@@ -79,24 +66,30 @@ public:
{
}
// VFALCO TODO Figure out a way to construct the LoadSource object with
// the proper name instead of renaming it later.
//
void rename (std::string const& name)
{
mName = name;
}
std::string const& getName ()
std::string const& getName () const
{
return mName;
}
bool isPrivileged () const
bool isPrivileged () const
{
return (mFlags & lsfPrivileged) != 0;
}
void setPrivileged ()
void setPrivileged ()
{
mFlags |= lsfPrivileged;
}
int getBalance () const
int getBalance () const
{
return mBalance;
}
@@ -105,16 +98,18 @@ public:
{
return mLogged;
}
void clearLogged ()
{
mLogged = false;
}
void setOutbound ()
void setOutbound ()
{
mFlags |= lsfOutbound;
}
bool isOutbound () const
bool isOutbound () const
{
return (mFlags & lsfOutbound) != 0;
}
@@ -132,43 +127,89 @@ private:
class LoadManager
{
public:
LoadManager (int creditRate = 100, int creditLimit = 500, int debitWarn = -500, int debitLimit = -1000);
LoadManager (int creditRate = 100,
int creditLimit = 500,
int debitWarn = -500,
int debitLimit = -1000);
~LoadManager ();
void init ();
int getCreditRate () const;
int getCreditLimit () const;
int getDebitWarn () const;
int getDebitLimit () const;
void setCreditRate (int);
void setCreditLimit (int);
void setDebitWarn (int);
void setDebitLimit (int);
bool shouldWarn (LoadSource&) const;
bool shouldCutoff (LoadSource&) const;
bool adjust (LoadSource&, int credits) const; // return value: false=balance okay, true=warn/cutoff
bool adjust (LoadSource&, LoadType l) const;
void logWarning (const std::string&) const;
void logDisconnect (const std::string&) const;
int getCost (LoadType t)
int getCost (LoadType t) const
{
return mCosts[static_cast<int> (t)].mCost;
return mCosts [static_cast <int> (t)].mCost;
}
void noDeadLock ();
void arm ()
{
mArmed = true;
}
private:
void canonicalize (LoadSource&, int upTime) const;
void addLoadCost (const LoadCost& c)
class Cost
{
mCosts[static_cast<int> (c.mType)] = c;
public:
Cost ()
: mType ()
, mCost (0)
, mCategories (0)
{
}
Cost (LoadType typeOfLoad, int cost, int category)
: mType (typeOfLoad)
, mCost (cost)
, mCategories (category)
{
}
public:
// VFALCO TODO Make these private
LoadType mType;
int mCost;
int mCategories;
};
void canonicalize (LoadSource&, int upTime) const;
void addCost (const Cost& c)
{
mCosts [static_cast <int> (c.mType)] = c;
}
// VFALCO NOTE Where's the thread object? It's not a data member...
//
void threadEntry ();
private:
@@ -182,9 +223,9 @@ private:
int mDeadLock; // Detect server deadlocks
mutable boost::mutex mLock;
mutable boost::mutex mLock; // VFALCO TODO Replace with juce::Mutex and remove the mutable attribute
std::vector<LoadCost> mCosts;
std::vector <Cost> mCosts;
};
#endif

View File

@@ -3,6 +3,8 @@
// Monitors load levels and response times
// VFALCO TODO Rename this. Having both LoadManager and LoadMonitor is confusing.
//
class LoadMonitor
{
public:

View File

@@ -95,7 +95,7 @@ Json::Value PathRequest::doCreate (Ledger::ref lrLedger, const Json::Value& valu
if (mValid)
{
RLCache::pointer cache = boost::make_shared<RLCache> (lrLedger);
RippleLineCache::pointer cache = boost::make_shared<RippleLineCache> (lrLedger);
doUpdate (cache, true);
}
}
@@ -220,7 +220,7 @@ Json::Value PathRequest::doStatus (const Json::Value&)
return jvStatus;
}
bool PathRequest::doUpdate (RLCache::ref cache, bool fast)
bool PathRequest::doUpdate (RippleLineCache::ref cache, bool fast)
{
boost::recursive_mutex::scoped_lock sl (mLock);
jvStatus = Json::objectValue;
@@ -319,7 +319,7 @@ void PathRequest::updateAll (Ledger::ref ledger, bool newOnly)
if (requests.empty ())
return;
RLCache::pointer cache = boost::make_shared<RLCache> (ledger);
RippleLineCache::pointer cache = boost::make_shared<RippleLineCache> (ledger);
BOOST_FOREACH (wref wRequest, requests)
{

View File

@@ -1,22 +1,12 @@
#ifndef _PFREQUEST__H
#define _PFREQUEST__H
#include <set>
#include <vector>
#include <boost/thread/recursive_mutex.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/weak_ptr.hpp>
#include "Pathfinder.h"
#ifndef RIPPLE_PATHREQUEST_H
#define RIPPLE_PATHREQUEST_H
// A pathfinding request submitted by a client
// The request issuer must maintain a strong pointer
class InfoSub;
class STAmount;
class RLCache;
class RippleLineCache;
// Return values from parseJson <0 = invalid, >0 = valid
#define PFR_PJ_INVALID -1
@@ -45,7 +35,7 @@ public:
Json::Value doClose (const Json::Value&);
Json::Value doStatus (const Json::Value&);
bool doUpdate (const boost::shared_ptr<RLCache>&, bool fast); // update jvStatus
bool doUpdate (const boost::shared_ptr<RippleLineCache>&, bool fast); // update jvStatus
static void updateAll (const boost::shared_ptr<Ledger>& ledger, bool newOnly);

View File

@@ -0,0 +1,787 @@
// TODO:
// - Do automatic bridging via XRP.
//
// OPTIMIZE: When calculating path increment, note if increment consumes all liquidity. No need to revisit path in the future if
// all liquidity is used.
//
class RippleCalc; // for logging
std::size_t hash_value (const aciSource& asValue)
{
std::size_t seed = 0;
asValue.get<0> ().hash_combine (seed);
asValue.get<1> ().hash_combine (seed);
asValue.get<2> ().hash_combine (seed);
return seed;
}
// Compare the non-calculated fields.
bool PathState::Node::operator== (const Node& pnOther) const
{
return pnOther.uFlags == uFlags
&& pnOther.uAccountID == uAccountID
&& pnOther.uCurrencyID == uCurrencyID
&& pnOther.uIssuerID == uIssuerID;
}
// This is for debugging not end users. Output names can be changed without warning.
Json::Value PathState::Node::getJson () const
{
Json::Value jvNode (Json::objectValue);
Json::Value jvFlags (Json::arrayValue);
jvNode["type"] = uFlags;
if (isSetBit (uFlags, STPathElement::typeAccount) || !!uAccountID)
jvFlags.append (!!isSetBit (uFlags, STPathElement::typeAccount) == !!uAccountID ? "account" : "-account");
if (isSetBit (uFlags, STPathElement::typeCurrency) || !!uCurrencyID)
jvFlags.append (!!isSetBit (uFlags, STPathElement::typeCurrency) == !!uCurrencyID ? "currency" : "-currency");
if (isSetBit (uFlags, STPathElement::typeIssuer) || !!uIssuerID)
jvFlags.append (!!isSetBit (uFlags, STPathElement::typeIssuer) == !!uIssuerID ? "issuer" : "-issuer");
jvNode["flags"] = jvFlags;
if (!!uAccountID)
jvNode["account"] = RippleAddress::createHumanAccountID (uAccountID);
if (!!uCurrencyID)
jvNode["currency"] = STAmount::createHumanCurrency (uCurrencyID);
if (!!uIssuerID)
jvNode["issuer"] = RippleAddress::createHumanAccountID (uIssuerID);
if (saRevRedeem)
jvNode["rev_redeem"] = saRevRedeem.getFullText ();
if (saRevIssue)
jvNode["rev_issue"] = saRevIssue.getFullText ();
if (saRevDeliver)
jvNode["rev_deliver"] = saRevDeliver.getFullText ();
if (saFwdRedeem)
jvNode["fwd_redeem"] = saFwdRedeem.getFullText ();
if (saFwdIssue)
jvNode["fwd_issue"] = saFwdIssue.getFullText ();
if (saFwdDeliver)
jvNode["fwd_deliver"] = saFwdDeliver.getFullText ();
return jvNode;
}
//
// PathState implementation
//
// Return true, iff lhs has less priority than rhs.
bool PathState::lessPriority (PathState& lhs, PathState& rhs)
{
// First rank is quality.
if (lhs.uQuality != rhs.uQuality)
return lhs.uQuality > rhs.uQuality; // Bigger is worse.
// Second rank is best quantity.
if (lhs.saOutPass != rhs.saOutPass)
return lhs.saOutPass < rhs.saOutPass; // Smaller is worse.
// Third rank is path index.
return lhs.mIndex > rhs.mIndex; // Bigger is worse.
}
// Make sure last path node delivers to uAccountID: uCurrencyID from uIssuerID.
//
// If the unadded next node as specified by arguments would not work as is, then add the necessary nodes so it would work.
//
// Rules:
// - Currencies must be converted via an offer.
// - A node names it's output.
// - A ripple nodes output issuer must be the node's account or the next node's account.
// - Offers can only go directly to another offer if the currency and issuer are an exact match.
// - Real issuers must be specified for non-XRP.
TER PathState::pushImply (
const uint160& uAccountID, // --> Delivering to this account.
const uint160& uCurrencyID, // --> Delivering this currency.
const uint160& uIssuerID) // --> Delivering this issuer.
{
const Node& pnPrv = vpnNodes.back ();
TER terResult = tesSUCCESS;
WriteLog (lsTRACE, RippleCalc) << "pushImply> "
<< RippleAddress::createHumanAccountID (uAccountID)
<< " " << STAmount::createHumanCurrency (uCurrencyID)
<< " " << RippleAddress::createHumanAccountID (uIssuerID);
if (pnPrv.uCurrencyID != uCurrencyID)
{
// Currency is different, need to convert via an offer.
terResult = pushNode ( // Offer.
!!uCurrencyID
? STPathElement::typeCurrency | STPathElement::typeIssuer
: STPathElement::typeCurrency,
ACCOUNT_XRP, // Placeholder for offers.
uCurrencyID, // The offer's output is what is now wanted.
uIssuerID);
}
const Node& pnBck = vpnNodes.back ();
// For ripple, non-XRP, ensure the issuer is on at least one side of the transaction.
if (tesSUCCESS == terResult
&& !!uCurrencyID // Not XRP.
&& (pnBck.uAccountID != uIssuerID // Previous is not issuing own IOUs.
&& uAccountID != uIssuerID)) // Current is not receiving own IOUs.
{
// Need to ripple through uIssuerID's account.
terResult = pushNode (
STPathElement::typeAccount | STPathElement::typeCurrency | STPathElement::typeIssuer,
uIssuerID, // Intermediate account is the needed issuer.
uCurrencyID,
uIssuerID);
}
WriteLog (lsTRACE, RippleCalc) << boost::str (boost::format ("pushImply< : %s") % transToken (terResult));
return terResult;
}
// Append a node and insert before it any implied nodes.
// Offers may go back to back.
// <-- terResult: tesSUCCESS, temBAD_PATH, terNO_ACCOUNT, terNO_AUTH, terNO_LINE, tecPATH_DRY
TER PathState::pushNode (
const int iType,
const uint160& uAccountID,
const uint160& uCurrencyID,
const uint160& uIssuerID)
{
Node pnCur;
const bool bFirst = vpnNodes.empty ();
const Node& pnPrv = bFirst ? Node () : vpnNodes.back ();
// true, iff node is a ripple account. false, iff node is an offer node.
const bool bAccount = isSetBit (iType, STPathElement::typeAccount);
// true, iff currency supplied.
// Currency is specified for the output of the current node.
const bool bCurrency = isSetBit (iType, STPathElement::typeCurrency);
// Issuer is specified for the output of the current node.
const bool bIssuer = isSetBit (iType, STPathElement::typeIssuer);
TER terResult = tesSUCCESS;
WriteLog (lsTRACE, RippleCalc) << "pushNode> "
<< iType
<< ": " << (bAccount ? RippleAddress::createHumanAccountID (uAccountID) : "-")
<< " " << (bCurrency ? STAmount::createHumanCurrency (uCurrencyID) : "-")
<< "/" << (bIssuer ? RippleAddress::createHumanAccountID (uIssuerID) : "-");
pnCur.uFlags = iType;
pnCur.uCurrencyID = bCurrency ? uCurrencyID : pnPrv.uCurrencyID;
if (iType & ~STPathElement::typeValidBits)
{
WriteLog (lsDEBUG, RippleCalc) << "pushNode: bad bits.";
terResult = temBAD_PATH;
}
else if (bIssuer && !pnCur.uCurrencyID)
{
WriteLog (lsDEBUG, RippleCalc) << "pushNode: issuer specified for XRP.";
terResult = temBAD_PATH;
}
else if (bIssuer && !uIssuerID)
{
WriteLog (lsDEBUG, RippleCalc) << "pushNode: specified bad issuer.";
terResult = temBAD_PATH;
}
else if (!bAccount && !bCurrency && !bIssuer)
{
WriteLog (lsDEBUG, RippleCalc) << "pushNode: offer must specify at least currency or issuer.";
terResult = temBAD_PATH;
}
else if (bAccount)
{
// Account link
pnCur.uAccountID = uAccountID;
pnCur.uIssuerID = bIssuer
? uIssuerID
: !!pnCur.uCurrencyID
? uAccountID
: ACCOUNT_XRP;
pnCur.saRevRedeem = STAmount (pnCur.uCurrencyID, uAccountID);
pnCur.saRevIssue = STAmount (pnCur.uCurrencyID, uAccountID);
pnCur.saRevDeliver = STAmount (pnCur.uCurrencyID, pnCur.uIssuerID);
pnCur.saFwdDeliver = pnCur.saRevDeliver;
if (bFirst)
{
// The first node is always correct as is.
nothing ();
}
else if (!uAccountID)
{
WriteLog (lsDEBUG, RippleCalc) << "pushNode: specified bad account.";
terResult = temBAD_PATH;
}
else
{
// Add required intermediate nodes to deliver to current account.
WriteLog (lsTRACE, RippleCalc) << "pushNode: imply for account.";
terResult = pushImply (
pnCur.uAccountID, // Current account.
pnCur.uCurrencyID, // Wanted currency.
!!pnCur.uCurrencyID ? uAccountID : ACCOUNT_XRP); // Account as wanted issuer.
// Note: pnPrv may no longer be the immediately previous node.
}
if (tesSUCCESS == terResult && !vpnNodes.empty ())
{
const Node& pnBck = vpnNodes.back ();
bool bBckAccount = isSetBit (pnBck.uFlags, STPathElement::typeAccount);
if (bBckAccount)
{
SLE::pointer sleRippleState = lesEntries.entryCache (ltRIPPLE_STATE, Ledger::getRippleStateIndex (pnBck.uAccountID, pnCur.uAccountID, pnPrv.uCurrencyID));
if (!sleRippleState)
{
WriteLog (lsTRACE, RippleCalc) << "pushNode: No credit line between "
<< RippleAddress::createHumanAccountID (pnBck.uAccountID)
<< " and "
<< RippleAddress::createHumanAccountID (pnCur.uAccountID)
<< " for "
<< STAmount::createHumanCurrency (pnCur.uCurrencyID)
<< "." ;
WriteLog (lsTRACE, RippleCalc) << getJson ();
terResult = terNO_LINE;
}
else
{
WriteLog (lsTRACE, RippleCalc) << "pushNode: Credit line found between "
<< RippleAddress::createHumanAccountID (pnBck.uAccountID)
<< " and "
<< RippleAddress::createHumanAccountID (pnCur.uAccountID)
<< " for "
<< STAmount::createHumanCurrency (pnCur.uCurrencyID)
<< "." ;
SLE::pointer sleBck = lesEntries.entryCache (ltACCOUNT_ROOT, Ledger::getAccountRootIndex (pnBck.uAccountID));
bool bHigh = pnBck.uAccountID > pnCur.uAccountID;
if (!sleBck)
{
WriteLog (lsWARNING, RippleCalc) << "pushNode: delay: can't receive IOUs from non-existent issuer: " << RippleAddress::createHumanAccountID (pnBck.uAccountID);
terResult = terNO_ACCOUNT;
}
else if (isSetBit (sleBck->getFieldU32 (sfFlags), lsfRequireAuth)
&& !isSetBit (sleRippleState->getFieldU32 (sfFlags), (bHigh ? lsfHighAuth : lsfLowAuth)))
{
WriteLog (lsWARNING, RippleCalc) << "pushNode: delay: can't receive IOUs from issuer without auth.";
terResult = terNO_AUTH;
}
if (tesSUCCESS == terResult)
{
STAmount saOwed = lesEntries.rippleOwed (pnCur.uAccountID, pnBck.uAccountID, pnCur.uCurrencyID);
STAmount saLimit;
if (!saOwed.isPositive ()
&& -saOwed >= (saLimit = lesEntries.rippleLimit (pnCur.uAccountID, pnBck.uAccountID, pnCur.uCurrencyID)))
{
WriteLog (lsWARNING, RippleCalc) << boost::str (boost::format ("pushNode: dry: saOwed=%s saLimit=%s")
% saOwed
% saLimit);
terResult = tecPATH_DRY;
}
}
}
}
}
if (tesSUCCESS == terResult)
{
vpnNodes.push_back (pnCur);
}
}
else
{
// Offer link
// Offers bridge a change in currency & issuer or just a change in issuer.
pnCur.uIssuerID = bIssuer
? uIssuerID
: !!pnCur.uCurrencyID
? !!pnPrv.uIssuerID
? pnPrv.uIssuerID // Default to previous issuer
: pnPrv.uAccountID // Or previous account if no previous issuer.
: ACCOUNT_XRP;
pnCur.saRateMax = saZero;
pnCur.saRevDeliver = STAmount (pnCur.uCurrencyID, pnCur.uIssuerID);
pnCur.saFwdDeliver = pnCur.saRevDeliver;
if (!!pnCur.uCurrencyID != !!pnCur.uIssuerID)
{
WriteLog (lsDEBUG, RippleCalc) << "pushNode: currency is inconsistent with issuer.";
terResult = temBAD_PATH;
}
else if (!!pnPrv.uAccountID)
{
// Previous is an account.
WriteLog (lsTRACE, RippleCalc) << "pushNode: imply for offer.";
// Insert intermediary issuer account if needed.
terResult = pushImply (
ACCOUNT_XRP, // Rippling, but offers don't have an account.
pnPrv.uCurrencyID,
pnPrv.uIssuerID);
}
if (tesSUCCESS == terResult)
{
vpnNodes.push_back (pnCur);
}
}
WriteLog (lsTRACE, RippleCalc) << boost::str (boost::format ("pushNode< : %s") % transToken (terResult));
return terResult;
}
// Set to an expanded path.
//
// terStatus = tesSUCCESS, temBAD_PATH, terNO_LINE, terNO_ACCOUNT, terNO_AUTH, or temBAD_PATH_LOOP
void PathState::setExpanded (
const LedgerEntrySet& lesSource,
const STPath& spSourcePath,
const uint160& uReceiverID,
const uint160& uSenderID
)
{
uQuality = 1; // Mark path as active.
const uint160 uMaxCurrencyID = saInReq.getCurrency ();
const uint160 uMaxIssuerID = saInReq.getIssuer ();
const uint160 uOutCurrencyID = saOutReq.getCurrency ();
const uint160 uOutIssuerID = saOutReq.getIssuer ();
const uint160 uSenderIssuerID = !!uMaxCurrencyID ? uSenderID : ACCOUNT_XRP; // Sender is always issuer for non-XRP.
WriteLog (lsDEBUG, RippleCalc) << boost::str (boost::format ("setExpanded> %s") % spSourcePath.getJson (0));
lesEntries = lesSource.duplicate ();
terStatus = tesSUCCESS;
// XRP with issuer is malformed.
if ((!uMaxCurrencyID && !!uMaxIssuerID) || (!uOutCurrencyID && !!uOutIssuerID))
terStatus = temBAD_PATH;
// Push sending node.
// For non-XRP, issuer is always sending account.
// - Trying to expand, not-compact.
// - Every issuer will be traversed through.
if (tesSUCCESS == terStatus)
terStatus = pushNode (
!!uMaxCurrencyID
? STPathElement::typeAccount | STPathElement::typeCurrency | STPathElement::typeIssuer
: STPathElement::typeAccount | STPathElement::typeCurrency,
uSenderID,
uMaxCurrencyID, // Max specifes the currency.
uSenderIssuerID);
WriteLog (lsDEBUG, RippleCalc) << boost::str (boost::format ("setExpanded: pushed: account=%s currency=%s issuer=%s")
% RippleAddress::createHumanAccountID (uSenderID)
% STAmount::createHumanCurrency (uMaxCurrencyID)
% RippleAddress::createHumanAccountID (uSenderIssuerID));
if (tesSUCCESS == terStatus
&& uMaxIssuerID != uSenderIssuerID) // Issuer was not same as sender.
{
// May have an implied account node.
// - If it was XRP, then issuers would have matched.
// Figure out next node properties for implied node.
const uint160 uNxtCurrencyID = spSourcePath.size ()
? spSourcePath.getElement (0).getCurrency () // Use next node.
: uOutCurrencyID; // Use send.
const uint160 uNxtAccountID = spSourcePath.size ()
? spSourcePath.getElement (0).getAccountID ()
: !!uOutCurrencyID
? uOutIssuerID == uReceiverID
? uReceiverID
: uOutIssuerID // Use implied node.
: ACCOUNT_XRP;
WriteLog (lsDEBUG, RippleCalc) << boost::str (boost::format ("setExpanded: implied check: uMaxIssuerID=%s uSenderIssuerID=%s uNxtCurrencyID=%s uNxtAccountID=%s")
% RippleAddress::createHumanAccountID (uMaxIssuerID)
% RippleAddress::createHumanAccountID (uSenderIssuerID)
% STAmount::createHumanCurrency (uNxtCurrencyID)
% RippleAddress::createHumanAccountID (uNxtAccountID));
// Can't just use push implied, because it can't compensate for next account.
if (!uNxtCurrencyID // Next is XRP, offer next. Must go through issuer.
|| uMaxCurrencyID != uNxtCurrencyID // Next is different currency, offer next...
|| uMaxIssuerID != uNxtAccountID) // Next is not implied issuer
{
WriteLog (lsDEBUG, RippleCalc) << boost::str (boost::format ("setExpanded: sender implied: account=%s currency=%s issuer=%s")
% RippleAddress::createHumanAccountID (uMaxIssuerID)
% STAmount::createHumanCurrency (uMaxCurrencyID)
% RippleAddress::createHumanAccountID (uMaxIssuerID));
// Add account implied by SendMax.
terStatus = pushNode (
!!uMaxCurrencyID
? STPathElement::typeAccount | STPathElement::typeCurrency | STPathElement::typeIssuer
: STPathElement::typeAccount | STPathElement::typeCurrency,
uMaxIssuerID,
uMaxCurrencyID,
uMaxIssuerID);
}
}
BOOST_FOREACH (const STPathElement & speElement, spSourcePath)
{
if (tesSUCCESS == terStatus)
{
WriteLog (lsDEBUG, RippleCalc) << boost::str (boost::format ("setExpanded: element in path:"));
terStatus = pushNode (speElement.getNodeType (), speElement.getAccountID (), speElement.getCurrency (), speElement.getIssuerID ());
}
}
const Node& pnPrv = vpnNodes.back ();
if (tesSUCCESS == terStatus
&& !!uOutCurrencyID // Next is not XRP
&& uOutIssuerID != uReceiverID // Out issuer is not receiver
&& (pnPrv.uCurrencyID != uOutCurrencyID // Previous will be an offer.
|| pnPrv.uAccountID != uOutIssuerID)) // Need the implied issuer.
{
// Add implied account.
WriteLog (lsDEBUG, RippleCalc) << boost::str (boost::format ("setExpanded: receiver implied: account=%s currency=%s issuer=%s")
% RippleAddress::createHumanAccountID (uOutIssuerID)
% STAmount::createHumanCurrency (uOutCurrencyID)
% RippleAddress::createHumanAccountID (uOutIssuerID));
terStatus = pushNode (
!!uOutCurrencyID
? STPathElement::typeAccount | STPathElement::typeCurrency | STPathElement::typeIssuer
: STPathElement::typeAccount | STPathElement::typeCurrency,
uOutIssuerID,
uOutCurrencyID,
uOutIssuerID);
}
if (tesSUCCESS == terStatus)
{
// Create receiver node.
// Last node is always an account.
terStatus = pushNode (
!!uOutCurrencyID
? STPathElement::typeAccount | STPathElement::typeCurrency | STPathElement::typeIssuer
: STPathElement::typeAccount | STPathElement::typeCurrency,
uReceiverID, // Receive to output
uOutCurrencyID, // Desired currency
uReceiverID);
}
if (tesSUCCESS == terStatus)
{
// Look for first mention of source in nodes and detect loops.
// Note: The output is not allowed to be a source.
const unsigned int uNodes = vpnNodes.size ();
for (unsigned int uNode = 0; tesSUCCESS == terStatus && uNode != uNodes; ++uNode)
{
const Node& pnCur = vpnNodes[uNode];
if (!umForward.insert (std::make_pair (boost::make_tuple (pnCur.uAccountID, pnCur.uCurrencyID, pnCur.uIssuerID), uNode)).second)
{
// Failed to insert. Have a loop.
WriteLog (lsDEBUG, RippleCalc) << boost::str (boost::format ("setExpanded: loop detected: %s")
% getJson ());
terStatus = temBAD_PATH_LOOP;
}
}
}
WriteLog (lsDEBUG, RippleCalc) << boost::str (boost::format ("setExpanded: in=%s/%s out=%s/%s %s")
% STAmount::createHumanCurrency (uMaxCurrencyID)
% RippleAddress::createHumanAccountID (uMaxIssuerID)
% STAmount::createHumanCurrency (uOutCurrencyID)
% RippleAddress::createHumanAccountID (uOutIssuerID)
% getJson ());
}
// Set to a canonical path.
// - Remove extra elements
// - Assumes path is expanded.
//
// We do canonicalization to:
// - Prevent waste in the ledger.
// - Allow longer paths to be specified than would otherwise be allowed.
//
// Optimization theory:
// - Can omit elements that the expansion routine derives.
// - Can pack some elements into other elements.
//
// Rules:
// - SendMax if not specified, defaults currency to send and if not sending XRP defaults issuer to sender.
// - All paths start with the sender account.
// - Currency and issuer is from SendMax.
// - All paths end with the destination account.
//
// Optimization:
// - An XRP output implies an offer node or destination node is next.
// - A change in currency implies an offer node.
// - A change in issuer...
void PathState::setCanonical (
const PathState& psExpanded
)
{
assert (false);
saInAct = psExpanded.saInAct;
saOutAct = psExpanded.saOutAct;
const uint160 uMaxCurrencyID = saInAct.getCurrency ();
const uint160 uMaxIssuerID = saInAct.getIssuer ();
const uint160 uOutCurrencyID = saOutAct.getCurrency ();
const uint160 uOutIssuerID = saOutAct.getIssuer ();
unsigned int uNode = 0;
unsigned int uEnd = psExpanded.vpnNodes.size (); // The node, indexed by 0, not to include.
uint160 uDstAccountID = psExpanded.vpnNodes[uEnd].uAccountID; // FIXME: This can't be right
uint160 uAccountID = psExpanded.vpnNodes[0].uAccountID;
uint160 uCurrencyID = uMaxCurrencyID;
uint160 uIssuerID = uMaxIssuerID;
// Node 0 is a composite of the sending account and saInAct.
++uNode; // skip node 0
// Last node is implied: Always skip last node
--uEnd; // skip last node
// saInAct
// - currency is always the same as vpnNodes[0].
#if 1
if (uNode != uEnd && uMaxIssuerID != uAccountID)
{
// saInAct issuer is not the sender. This forces an implied node.
// WriteLog (lsDEBUG, RippleCalc) << boost::str(boost::format("setCanonical: in diff: uNode=%d uEnd=%d") % uNode % uEnd);
// skip node 1
uIssuerID = psExpanded.vpnNodes[uNode].uIssuerID;
++uNode;
}
#else
if (uNode != uEnd)
{
// Have another node
bool bKeep = false;
if (uMaxIssuerID != uAccountID)
{
}
if (uMaxCurrencyID) // Not sending XRP.
{
// Node 1 must be an account.
if (uMaxIssuerID != uAccountID)
{
// Node 1 is required to specify issuer.
bKeep = true;
}
else
{
// Node 1 must be an account
}
}
else
{
// Node 1 must be an order book.
bKeep = true;
}
if (bKeep)
{
uCurrencyID = psExpanded.vpnNodes[uNode].uCurrencyID;
uIssuerID = psExpanded.vpnNodes[uNode].uIssuerID;
++uNode; // Keep it.
}
}
#endif
if (uNode != uEnd && !!uOutCurrencyID && uOutIssuerID != uDstAccountID)
{
// WriteLog (lsDEBUG, RippleCalc) << boost::str(boost::format("setCanonical: out diff: uNode=%d uEnd=%d") % uNode % uEnd);
// The next to last node is saOutAct if an issuer different from receiver is supplied.
// The next to last node can be implied.
--uEnd;
}
const Node& pnEnd = psExpanded.vpnNodes[uEnd];
if (uNode != uEnd
&& !pnEnd.uAccountID && pnEnd.uCurrencyID == uOutCurrencyID && pnEnd.uIssuerID == uOutIssuerID)
{
// The current end node is an offer converting to saOutAct's currency and issuer and can be implied.
// WriteLog (lsDEBUG, RippleCalc) << boost::str(boost::format("setCanonical: out offer: uNode=%d uEnd=%d") % uNode % uEnd);
--uEnd;
}
// Do not include uEnd.
for (; uNode != uEnd; ++uNode)
{
// WriteLog (lsDEBUG, RippleCalc) << boost::str(boost::format("setCanonical: loop: uNode=%d uEnd=%d") % uNode % uEnd);
const Node& pnPrv = psExpanded.vpnNodes[uNode - 1];
const Node& pnCur = psExpanded.vpnNodes[uNode];
const Node& pnNxt = psExpanded.vpnNodes[uNode + 1];
const bool bCurAccount = isSetBit (pnCur.uFlags, STPathElement::typeAccount);
bool bSkip = false;
if (bCurAccount)
{
// Currently at an account.
// Output is non-XRP and issuer is account.
if (!!pnCur.uCurrencyID && pnCur.uIssuerID == pnCur.uAccountID)
{
// Account issues itself.
// XXX Not good enough. Previous account must mention it.
bSkip = true;
}
}
else
{
// Currently at an offer.
const bool bPrvAccount = isSetBit (pnPrv.uFlags, STPathElement::typeAccount);
const bool bNxtAccount = isSetBit (pnNxt.uFlags, STPathElement::typeAccount);
if (bPrvAccount && bNxtAccount // Offer surrounded by accounts.
&& pnPrv.uCurrencyID != pnNxt.uCurrencyID)
{
// Offer can be implied by currency change.
// XXX What about issuer?
bSkip = true;
}
}
if (!bSkip)
{
// Copy node
Node pnNew;
bool bSetAccount = bCurAccount;
bool bSetCurrency = uCurrencyID != pnCur.uCurrencyID;
// XXX What if we need the next account because we want to skip it?
bool bSetIssuer = !uCurrencyID && uIssuerID != pnCur.uIssuerID;
pnNew.uFlags = (bSetAccount ? STPathElement::typeAccount : 0)
| (bSetCurrency ? STPathElement::typeCurrency : 0)
| (bSetIssuer ? STPathElement::typeIssuer : 0);
if (bSetAccount)
pnNew.uAccountID = pnCur.uAccountID;
if (bSetCurrency)
{
pnNew.uCurrencyID = pnCur.uCurrencyID;
uCurrencyID = pnNew.uCurrencyID;
}
if (bSetIssuer)
pnNew.uIssuerID = pnCur.uIssuerID;
// XXX ^^^ What about setting uIssuerID?
if (bSetCurrency && !uCurrencyID)
uIssuerID.zero ();
vpnNodes.push_back (pnNew);
}
}
WriteLog (lsDEBUG, RippleCalc) << boost::str (boost::format ("setCanonical: in=%s/%s out=%s/%s %s")
% STAmount::createHumanCurrency (uMaxCurrencyID)
% RippleAddress::createHumanAccountID (uMaxIssuerID)
% STAmount::createHumanCurrency (uOutCurrencyID)
% RippleAddress::createHumanAccountID (uOutIssuerID)
% getJson ());
}
// This is for debugging not end users. Output names can be changed without warning.
Json::Value PathState::getJson () const
{
Json::Value jvPathState (Json::objectValue);
Json::Value jvNodes (Json::arrayValue);
BOOST_FOREACH (const Node & pnNode, vpnNodes)
{
jvNodes.append (pnNode.getJson ());
}
jvPathState["status"] = terStatus;
jvPathState["index"] = mIndex;
jvPathState["nodes"] = jvNodes;
if (saInReq)
jvPathState["in_req"] = saInReq.getJson (0);
if (saInAct)
jvPathState["in_act"] = saInAct.getJson (0);
if (saInPass)
jvPathState["in_pass"] = saInPass.getJson (0);
if (saOutReq)
jvPathState["out_req"] = saOutReq.getJson (0);
if (saOutAct)
jvPathState["out_act"] = saOutAct.getJson (0);
if (saOutPass)
jvPathState["out_pass"] = saOutPass.getJson (0);
if (uQuality)
jvPathState["uQuality"] = boost::str (boost::format ("%d") % uQuality);
return jvPathState;
}

View File

@@ -0,0 +1,158 @@
#ifndef RIPPLE_PATHSTATE_H
#define RIPPLE_PATHSTATE_H
// account id, currency id, issuer id :: node
typedef boost::tuple <uint160, uint160, uint160> aciSource;
typedef boost::unordered_map <aciSource, unsigned int> curIssuerNode; // Map of currency, issuer to node index.
typedef boost::unordered_map <aciSource, unsigned int>::const_iterator curIssuerNodeConstIterator;
extern std::size_t hash_value (const aciSource& asValue);
// Holds a path state under incremental application.
class PathState
{
public:
class Node
{
public:
bool operator == (Node const& pnOther) const;
Json::Value getJson () const;
public:
uint16 uFlags; // --> From path.
uint160 uAccountID; // --> Accounts: Recieving/sending account.
uint160 uCurrencyID; // --> Accounts: Receive and send, Offers: send.
// --- For offer's next has currency out.
uint160 uIssuerID; // --> Currency's issuer
STAmount saTransferRate; // Transfer rate for uIssuerID.
// Computed by Reverse.
STAmount saRevRedeem; // <-- Amount to redeem to next.
STAmount saRevIssue; // <-- Amount to issue to next limited by credit and outstanding IOUs.
// Issue isn't used by offers.
STAmount saRevDeliver; // <-- Amount to deliver to next regardless of fee.
// Computed by forward.
STAmount saFwdRedeem; // <-- Amount node will redeem to next.
STAmount saFwdIssue; // <-- Amount node will issue to next.
// Issue isn't used by offers.
STAmount saFwdDeliver; // <-- Amount to deliver to next regardless of fee.
// For offers:
STAmount saRateMax;
// Directory
uint256 uDirectTip; // Current directory.
uint256 uDirectEnd; // Next order book.
bool bDirectAdvance; // Need to advance directory.
SLE::pointer sleDirectDir;
STAmount saOfrRate; // For correct ratio.
// PaymentNode
bool bEntryAdvance; // Need to advance entry.
unsigned int uEntry;
uint256 uOfferIndex;
SLE::pointer sleOffer;
uint160 uOfrOwnerID;
bool bFundsDirty; // Need to refresh saOfferFunds, saTakerPays, & saTakerGets.
STAmount saOfferFunds;
STAmount saTakerPays;
STAmount saTakerGets;
};
public:
typedef boost::shared_ptr<PathState> pointer;
typedef const boost::shared_ptr<PathState>& ref;
public:
PathState* setIndex (const int iIndex)
{
mIndex = iIndex;
return this;
}
int getIndex ()
{
return mIndex;
};
PathState (
const STAmount& saSend,
const STAmount& saSendMax)
: saInReq (saSendMax)
, saOutReq (saSend)
{
}
PathState (const PathState& psSrc,
bool bUnused)
: saInReq (psSrc.saInReq)
, saOutReq (psSrc.saOutReq)
{
}
void setExpanded (
const LedgerEntrySet& lesSource,
const STPath& spSourcePath,
const uint160& uReceiverID,
const uint160& uSenderID
);
void setCanonical (
const PathState& psExpanded
);
Json::Value getJson () const;
#if 0
static PathState::pointer createCanonical (
PathState& ref pspExpanded
)
{
PathState::pointer pspNew = boost::make_shared<PathState> (pspExpanded->saOutAct, pspExpanded->saInAct);
pspNew->setCanonical (pspExpanded);
return pspNew;
}
#endif
static bool lessPriority (PathState& lhs, PathState& rhs);
public:
TER terStatus;
std::vector<Node> vpnNodes;
// When processing, don't want to complicate directory walking with deletion.
std::vector<uint256> vUnfundedBecame; // Offers that became unfunded or were completely consumed.
// First time scanning foward, as part of path contruction, a funding source was mentioned for accounts. Source may only be
// used there.
curIssuerNode umForward; // Map of currency, issuer to node index.
// First time working in reverse a funding source was used.
// Source may only be used there if not mentioned by an account.
curIssuerNode umReverse; // Map of currency, issuer to node index.
LedgerEntrySet lesEntries;
int mIndex; // Index/rank amoung siblings.
uint64 uQuality; // 0 = no quality/liquity left.
const STAmount& saInReq; // --> Max amount to spend by sender.
STAmount saInAct; // --> Amount spent by sender so far.
STAmount saInPass; // <-- Amount spent by sender.
const STAmount& saOutReq; // --> Amount to send.
STAmount saOutAct; // --> Amount actually sent so far.
STAmount saOutPass; // <-- Amount actually sent.
bool bConsumed; // If true, use consumes full liquidity. False, may or may not.
private:
TER pushNode (const int iType, const uint160& uAccountID, const uint160& uCurrencyID, const uint160& uIssuerID);
TER pushImply (const uint160& uAccountID, const uint160& uCurrencyID, const uint160& uIssuerID);
};
#endif

View File

@@ -135,7 +135,7 @@ static int getEffectiveLength (const STPath& spPath)
return length;
}
Pathfinder::Pathfinder (RLCache::ref cache,
Pathfinder::Pathfinder (RippleLineCache::ref cache,
const RippleAddress& uSrcAccountID, const RippleAddress& uDstAccountID,
const uint160& uSrcCurrencyID, const uint160& uSrcIssuerID, const STAmount& saDstAmount, bool& bValid)
: mSrcAccountID (uSrcAccountID.getAccountID ()),
@@ -792,18 +792,6 @@ boost::unordered_set<uint160> usAccountDestCurrencies (const RippleAddress& raAc
return usCurrencies;
}
AccountItems& RLCache::getRippleLines (const uint160& accountID)
{
boost::mutex::scoped_lock sl (mLock);
boost::unordered_map<uint160, AccountItems::pointer>::iterator it = mRLMap.find (accountID);
if (it == mRLMap.end ())
it = mRLMap.insert (std::make_pair (accountID, boost::make_shared<AccountItems>
(boost::cref (accountID), boost::cref (mLedger), AccountItem::pointer (new RippleState ())))).first;
return *it->second;
}
bool Pathfinder::matchesOrigin (const uint160& currency, const uint160& issuer)
{
return (currency == mSrcCurrencyID) && (issuer == mSrcIssuerID);

View File

@@ -1,11 +1,7 @@
#ifndef __PATHFINDER__
#define __PATHFINDER__
#include <boost/shared_ptr.hpp>
#include "RippleCalc.h"
#include "OrderBookDB.h"
#ifndef RIPPLE_PATHFINDER_H
#define RIPPLE_PATHFINDER_H
// VFALCO TODO Remove this unused stuff?
#if 0
//
// This is a very simple implementation. This can be made way better.
@@ -32,33 +28,10 @@ public:
};
#endif
class RLCache
{
public:
typedef boost::shared_ptr<RLCache> pointer;
typedef const pointer& ref;
RLCache (Ledger::ref l) : mLedger (l)
{
;
}
Ledger::ref getLedger ()
{
return mLedger;
}
AccountItems& getRippleLines (const uint160& accountID);
private:
boost::mutex mLock;
Ledger::pointer mLedger;
boost::unordered_map<uint160, AccountItems::pointer> mRLMap;
};
class Pathfinder
{
public:
Pathfinder (RLCache::ref cache,
Pathfinder (RippleLineCache::ref cache,
const RippleAddress& srcAccountID, const RippleAddress& dstAccountID,
const uint160& srcCurrencyID, const uint160& srcIssuerID, const STAmount& dstAmount, bool& bValid);
@@ -66,6 +39,19 @@ public:
bool bDefaultPath (const STPath& spPath);
private:
// void addOptions(PathOption::pointer tail);
// returns true if any building paths are now complete?
bool checkComplete (STPathSet& retPathSet);
// void addPathOption(PathOption::pointer pathOption);
bool matchesOrigin (const uint160& currency, const uint160& issuer);
int getPathsOut (const uint160& currency, const uint160& accountID,
bool isAuthRequired, bool isDestCurrency, const uint160& dest);
private:
uint160 mSrcAccountID;
uint160 mDstAccountID;
@@ -77,25 +63,13 @@ private:
Ledger::pointer mLedger;
PathState::pointer mPsDefault;
LoadEvent::pointer m_loadEvent;
RLCache::pointer mRLCache;
RippleLineCache::pointer mRLCache;
boost::unordered_map<uint160, AccountItems::pointer> mRLMap;
boost::unordered_map<std::pair<uint160, uint160>, int> mPOMap;
// std::list<PathOption::pointer> mBuildingPaths;
// std::list<PathOption::pointer> mCompletePaths;
// void addOptions(PathOption::pointer tail);
// returns true if any building paths are now complete?
bool checkComplete (STPathSet& retPathSet);
// void addPathOption(PathOption::pointer pathOption);
bool matchesOrigin (const uint160& currency, const uint160& issuer);
int getPathsOut (const uint160& currency, const uint160& accountID,
bool isAuthRequired, bool isDestCurrency, const uint160& dest);
};
boost::unordered_set<uint160> usAccountDestCurrencies (const RippleAddress& raAccountID, Ledger::ref lrLedger,
@@ -105,5 +79,3 @@ boost::unordered_set<uint160> usAccountSourceCurrencies (const RippleAddress& ra
bool includeXRP);
#endif
// vim:ts=4

View File

@@ -7,824 +7,6 @@
SETUP_LOG (RippleCalc)
std::size_t hash_value (const aciSource& asValue)
{
std::size_t seed = 0;
asValue.get<0> ().hash_combine (seed);
asValue.get<1> ().hash_combine (seed);
asValue.get<2> ().hash_combine (seed);
return seed;
}
// Compare the non-calculated fields.
bool PaymentNode::operator== (const PaymentNode& pnOther) const
{
return pnOther.uFlags == uFlags
&& pnOther.uAccountID == uAccountID
&& pnOther.uCurrencyID == uCurrencyID
&& pnOther.uIssuerID == uIssuerID;
}
// This is for debugging not end users. Output names can be changed without warning.
Json::Value PaymentNode::getJson () const
{
Json::Value jvNode (Json::objectValue);
Json::Value jvFlags (Json::arrayValue);
jvNode["type"] = uFlags;
if (isSetBit (uFlags, STPathElement::typeAccount) || !!uAccountID)
jvFlags.append (!!isSetBit (uFlags, STPathElement::typeAccount) == !!uAccountID ? "account" : "-account");
if (isSetBit (uFlags, STPathElement::typeCurrency) || !!uCurrencyID)
jvFlags.append (!!isSetBit (uFlags, STPathElement::typeCurrency) == !!uCurrencyID ? "currency" : "-currency");
if (isSetBit (uFlags, STPathElement::typeIssuer) || !!uIssuerID)
jvFlags.append (!!isSetBit (uFlags, STPathElement::typeIssuer) == !!uIssuerID ? "issuer" : "-issuer");
jvNode["flags"] = jvFlags;
if (!!uAccountID)
jvNode["account"] = RippleAddress::createHumanAccountID (uAccountID);
if (!!uCurrencyID)
jvNode["currency"] = STAmount::createHumanCurrency (uCurrencyID);
if (!!uIssuerID)
jvNode["issuer"] = RippleAddress::createHumanAccountID (uIssuerID);
if (saRevRedeem)
jvNode["rev_redeem"] = saRevRedeem.getFullText ();
if (saRevIssue)
jvNode["rev_issue"] = saRevIssue.getFullText ();
if (saRevDeliver)
jvNode["rev_deliver"] = saRevDeliver.getFullText ();
if (saFwdRedeem)
jvNode["fwd_redeem"] = saFwdRedeem.getFullText ();
if (saFwdIssue)
jvNode["fwd_issue"] = saFwdIssue.getFullText ();
if (saFwdDeliver)
jvNode["fwd_deliver"] = saFwdDeliver.getFullText ();
return jvNode;
}
//
// PathState implementation
//
// Return true, iff lhs has less priority than rhs.
bool PathState::lessPriority (PathState& lhs, PathState& rhs)
{
// First rank is quality.
if (lhs.uQuality != rhs.uQuality)
return lhs.uQuality > rhs.uQuality; // Bigger is worse.
// Second rank is best quantity.
if (lhs.saOutPass != rhs.saOutPass)
return lhs.saOutPass < rhs.saOutPass; // Smaller is worse.
// Third rank is path index.
return lhs.mIndex > rhs.mIndex; // Bigger is worse.
}
// Make sure last path node delivers to uAccountID: uCurrencyID from uIssuerID.
//
// If the unadded next node as specified by arguments would not work as is, then add the necessary nodes so it would work.
//
// Rules:
// - Currencies must be converted via an offer.
// - A node names it's output.
// - A ripple nodes output issuer must be the node's account or the next node's account.
// - Offers can only go directly to another offer if the currency and issuer are an exact match.
// - Real issuers must be specified for non-XRP.
TER PathState::pushImply (
const uint160& uAccountID, // --> Delivering to this account.
const uint160& uCurrencyID, // --> Delivering this currency.
const uint160& uIssuerID) // --> Delivering this issuer.
{
const PaymentNode& pnPrv = vpnNodes.back ();
TER terResult = tesSUCCESS;
WriteLog (lsTRACE, RippleCalc) << "pushImply> "
<< RippleAddress::createHumanAccountID (uAccountID)
<< " " << STAmount::createHumanCurrency (uCurrencyID)
<< " " << RippleAddress::createHumanAccountID (uIssuerID);
if (pnPrv.uCurrencyID != uCurrencyID)
{
// Currency is different, need to convert via an offer.
terResult = pushNode ( // Offer.
!!uCurrencyID
? STPathElement::typeCurrency | STPathElement::typeIssuer
: STPathElement::typeCurrency,
ACCOUNT_XRP, // Placeholder for offers.
uCurrencyID, // The offer's output is what is now wanted.
uIssuerID);
}
const PaymentNode& pnBck = vpnNodes.back ();
// For ripple, non-XRP, ensure the issuer is on at least one side of the transaction.
if (tesSUCCESS == terResult
&& !!uCurrencyID // Not XRP.
&& (pnBck.uAccountID != uIssuerID // Previous is not issuing own IOUs.
&& uAccountID != uIssuerID)) // Current is not receiving own IOUs.
{
// Need to ripple through uIssuerID's account.
terResult = pushNode (
STPathElement::typeAccount | STPathElement::typeCurrency | STPathElement::typeIssuer,
uIssuerID, // Intermediate account is the needed issuer.
uCurrencyID,
uIssuerID);
}
WriteLog (lsTRACE, RippleCalc) << boost::str (boost::format ("pushImply< : %s") % transToken (terResult));
return terResult;
}
// Append a node and insert before it any implied nodes.
// Offers may go back to back.
// <-- terResult: tesSUCCESS, temBAD_PATH, terNO_ACCOUNT, terNO_AUTH, terNO_LINE, tecPATH_DRY
TER PathState::pushNode (
const int iType,
const uint160& uAccountID,
const uint160& uCurrencyID,
const uint160& uIssuerID)
{
PaymentNode pnCur;
const bool bFirst = vpnNodes.empty ();
const PaymentNode& pnPrv = bFirst ? PaymentNode () : vpnNodes.back ();
// true, iff node is a ripple account. false, iff node is an offer node.
const bool bAccount = isSetBit (iType, STPathElement::typeAccount);
// true, iff currency supplied.
// Currency is specified for the output of the current node.
const bool bCurrency = isSetBit (iType, STPathElement::typeCurrency);
// Issuer is specified for the output of the current node.
const bool bIssuer = isSetBit (iType, STPathElement::typeIssuer);
TER terResult = tesSUCCESS;
WriteLog (lsTRACE, RippleCalc) << "pushNode> "
<< iType
<< ": " << (bAccount ? RippleAddress::createHumanAccountID (uAccountID) : "-")
<< " " << (bCurrency ? STAmount::createHumanCurrency (uCurrencyID) : "-")
<< "/" << (bIssuer ? RippleAddress::createHumanAccountID (uIssuerID) : "-");
pnCur.uFlags = iType;
pnCur.uCurrencyID = bCurrency ? uCurrencyID : pnPrv.uCurrencyID;
if (iType & ~STPathElement::typeValidBits)
{
WriteLog (lsDEBUG, RippleCalc) << "pushNode: bad bits.";
terResult = temBAD_PATH;
}
else if (bIssuer && !pnCur.uCurrencyID)
{
WriteLog (lsDEBUG, RippleCalc) << "pushNode: issuer specified for XRP.";
terResult = temBAD_PATH;
}
else if (bIssuer && !uIssuerID)
{
WriteLog (lsDEBUG, RippleCalc) << "pushNode: specified bad issuer.";
terResult = temBAD_PATH;
}
else if (!bAccount && !bCurrency && !bIssuer)
{
WriteLog (lsDEBUG, RippleCalc) << "pushNode: offer must specify at least currency or issuer.";
terResult = temBAD_PATH;
}
else if (bAccount)
{
// Account link
pnCur.uAccountID = uAccountID;
pnCur.uIssuerID = bIssuer
? uIssuerID
: !!pnCur.uCurrencyID
? uAccountID
: ACCOUNT_XRP;
pnCur.saRevRedeem = STAmount (pnCur.uCurrencyID, uAccountID);
pnCur.saRevIssue = STAmount (pnCur.uCurrencyID, uAccountID);
pnCur.saRevDeliver = STAmount (pnCur.uCurrencyID, pnCur.uIssuerID);
pnCur.saFwdDeliver = pnCur.saRevDeliver;
if (bFirst)
{
// The first node is always correct as is.
nothing ();
}
else if (!uAccountID)
{
WriteLog (lsDEBUG, RippleCalc) << "pushNode: specified bad account.";
terResult = temBAD_PATH;
}
else
{
// Add required intermediate nodes to deliver to current account.
WriteLog (lsTRACE, RippleCalc) << "pushNode: imply for account.";
terResult = pushImply (
pnCur.uAccountID, // Current account.
pnCur.uCurrencyID, // Wanted currency.
!!pnCur.uCurrencyID ? uAccountID : ACCOUNT_XRP); // Account as wanted issuer.
// Note: pnPrv may no longer be the immediately previous node.
}
if (tesSUCCESS == terResult && !vpnNodes.empty ())
{
const PaymentNode& pnBck = vpnNodes.back ();
bool bBckAccount = isSetBit (pnBck.uFlags, STPathElement::typeAccount);
if (bBckAccount)
{
SLE::pointer sleRippleState = lesEntries.entryCache (ltRIPPLE_STATE, Ledger::getRippleStateIndex (pnBck.uAccountID, pnCur.uAccountID, pnPrv.uCurrencyID));
if (!sleRippleState)
{
WriteLog (lsTRACE, RippleCalc) << "pushNode: No credit line between "
<< RippleAddress::createHumanAccountID (pnBck.uAccountID)
<< " and "
<< RippleAddress::createHumanAccountID (pnCur.uAccountID)
<< " for "
<< STAmount::createHumanCurrency (pnCur.uCurrencyID)
<< "." ;
WriteLog (lsTRACE, RippleCalc) << getJson ();
terResult = terNO_LINE;
}
else
{
WriteLog (lsTRACE, RippleCalc) << "pushNode: Credit line found between "
<< RippleAddress::createHumanAccountID (pnBck.uAccountID)
<< " and "
<< RippleAddress::createHumanAccountID (pnCur.uAccountID)
<< " for "
<< STAmount::createHumanCurrency (pnCur.uCurrencyID)
<< "." ;
SLE::pointer sleBck = lesEntries.entryCache (ltACCOUNT_ROOT, Ledger::getAccountRootIndex (pnBck.uAccountID));
bool bHigh = pnBck.uAccountID > pnCur.uAccountID;
if (!sleBck)
{
WriteLog (lsWARNING, RippleCalc) << "pushNode: delay: can't receive IOUs from non-existent issuer: " << RippleAddress::createHumanAccountID (pnBck.uAccountID);
terResult = terNO_ACCOUNT;
}
else if (isSetBit (sleBck->getFieldU32 (sfFlags), lsfRequireAuth)
&& !isSetBit (sleRippleState->getFieldU32 (sfFlags), (bHigh ? lsfHighAuth : lsfLowAuth)))
{
WriteLog (lsWARNING, RippleCalc) << "pushNode: delay: can't receive IOUs from issuer without auth.";
terResult = terNO_AUTH;
}
if (tesSUCCESS == terResult)
{
STAmount saOwed = lesEntries.rippleOwed (pnCur.uAccountID, pnBck.uAccountID, pnCur.uCurrencyID);
STAmount saLimit;
if (!saOwed.isPositive ()
&& -saOwed >= (saLimit = lesEntries.rippleLimit (pnCur.uAccountID, pnBck.uAccountID, pnCur.uCurrencyID)))
{
WriteLog (lsWARNING, RippleCalc) << boost::str (boost::format ("pushNode: dry: saOwed=%s saLimit=%s")
% saOwed
% saLimit);
terResult = tecPATH_DRY;
}
}
}
}
}
if (tesSUCCESS == terResult)
{
vpnNodes.push_back (pnCur);
}
}
else
{
// Offer link
// Offers bridge a change in currency & issuer or just a change in issuer.
pnCur.uIssuerID = bIssuer
? uIssuerID
: !!pnCur.uCurrencyID
? !!pnPrv.uIssuerID
? pnPrv.uIssuerID // Default to previous issuer
: pnPrv.uAccountID // Or previous account if no previous issuer.
: ACCOUNT_XRP;
pnCur.saRateMax = saZero;
pnCur.saRevDeliver = STAmount (pnCur.uCurrencyID, pnCur.uIssuerID);
pnCur.saFwdDeliver = pnCur.saRevDeliver;
if (!!pnCur.uCurrencyID != !!pnCur.uIssuerID)
{
WriteLog (lsDEBUG, RippleCalc) << "pushNode: currency is inconsistent with issuer.";
terResult = temBAD_PATH;
}
else if (!!pnPrv.uAccountID)
{
// Previous is an account.
WriteLog (lsTRACE, RippleCalc) << "pushNode: imply for offer.";
// Insert intermediary issuer account if needed.
terResult = pushImply (
ACCOUNT_XRP, // Rippling, but offers don't have an account.
pnPrv.uCurrencyID,
pnPrv.uIssuerID);
}
if (tesSUCCESS == terResult)
{
vpnNodes.push_back (pnCur);
}
}
WriteLog (lsTRACE, RippleCalc) << boost::str (boost::format ("pushNode< : %s") % transToken (terResult));
return terResult;
}
// Set to an expanded path.
//
// terStatus = tesSUCCESS, temBAD_PATH, terNO_LINE, terNO_ACCOUNT, terNO_AUTH, or temBAD_PATH_LOOP
void PathState::setExpanded (
const LedgerEntrySet& lesSource,
const STPath& spSourcePath,
const uint160& uReceiverID,
const uint160& uSenderID
)
{
uQuality = 1; // Mark path as active.
const uint160 uMaxCurrencyID = saInReq.getCurrency ();
const uint160 uMaxIssuerID = saInReq.getIssuer ();
const uint160 uOutCurrencyID = saOutReq.getCurrency ();
const uint160 uOutIssuerID = saOutReq.getIssuer ();
const uint160 uSenderIssuerID = !!uMaxCurrencyID ? uSenderID : ACCOUNT_XRP; // Sender is always issuer for non-XRP.
WriteLog (lsDEBUG, RippleCalc) << boost::str (boost::format ("setExpanded> %s") % spSourcePath.getJson (0));
lesEntries = lesSource.duplicate ();
terStatus = tesSUCCESS;
// XRP with issuer is malformed.
if ((!uMaxCurrencyID && !!uMaxIssuerID) || (!uOutCurrencyID && !!uOutIssuerID))
terStatus = temBAD_PATH;
// Push sending node.
// For non-XRP, issuer is always sending account.
// - Trying to expand, not-compact.
// - Every issuer will be traversed through.
if (tesSUCCESS == terStatus)
terStatus = pushNode (
!!uMaxCurrencyID
? STPathElement::typeAccount | STPathElement::typeCurrency | STPathElement::typeIssuer
: STPathElement::typeAccount | STPathElement::typeCurrency,
uSenderID,
uMaxCurrencyID, // Max specifes the currency.
uSenderIssuerID);
WriteLog (lsDEBUG, RippleCalc) << boost::str (boost::format ("setExpanded: pushed: account=%s currency=%s issuer=%s")
% RippleAddress::createHumanAccountID (uSenderID)
% STAmount::createHumanCurrency (uMaxCurrencyID)
% RippleAddress::createHumanAccountID (uSenderIssuerID));
if (tesSUCCESS == terStatus
&& uMaxIssuerID != uSenderIssuerID) // Issuer was not same as sender.
{
// May have an implied account node.
// - If it was XRP, then issuers would have matched.
// Figure out next node properties for implied node.
const uint160 uNxtCurrencyID = spSourcePath.size ()
? spSourcePath.getElement (0).getCurrency () // Use next node.
: uOutCurrencyID; // Use send.
const uint160 uNxtAccountID = spSourcePath.size ()
? spSourcePath.getElement (0).getAccountID ()
: !!uOutCurrencyID
? uOutIssuerID == uReceiverID
? uReceiverID
: uOutIssuerID // Use implied node.
: ACCOUNT_XRP;
WriteLog (lsDEBUG, RippleCalc) << boost::str (boost::format ("setExpanded: implied check: uMaxIssuerID=%s uSenderIssuerID=%s uNxtCurrencyID=%s uNxtAccountID=%s")
% RippleAddress::createHumanAccountID (uMaxIssuerID)
% RippleAddress::createHumanAccountID (uSenderIssuerID)
% STAmount::createHumanCurrency (uNxtCurrencyID)
% RippleAddress::createHumanAccountID (uNxtAccountID));
// Can't just use push implied, because it can't compensate for next account.
if (!uNxtCurrencyID // Next is XRP, offer next. Must go through issuer.
|| uMaxCurrencyID != uNxtCurrencyID // Next is different currency, offer next...
|| uMaxIssuerID != uNxtAccountID) // Next is not implied issuer
{
WriteLog (lsDEBUG, RippleCalc) << boost::str (boost::format ("setExpanded: sender implied: account=%s currency=%s issuer=%s")
% RippleAddress::createHumanAccountID (uMaxIssuerID)
% STAmount::createHumanCurrency (uMaxCurrencyID)
% RippleAddress::createHumanAccountID (uMaxIssuerID));
// Add account implied by SendMax.
terStatus = pushNode (
!!uMaxCurrencyID
? STPathElement::typeAccount | STPathElement::typeCurrency | STPathElement::typeIssuer
: STPathElement::typeAccount | STPathElement::typeCurrency,
uMaxIssuerID,
uMaxCurrencyID,
uMaxIssuerID);
}
}
BOOST_FOREACH (const STPathElement & speElement, spSourcePath)
{
if (tesSUCCESS == terStatus)
{
WriteLog (lsDEBUG, RippleCalc) << boost::str (boost::format ("setExpanded: element in path:"));
terStatus = pushNode (speElement.getNodeType (), speElement.getAccountID (), speElement.getCurrency (), speElement.getIssuerID ());
}
}
const PaymentNode& pnPrv = vpnNodes.back ();
if (tesSUCCESS == terStatus
&& !!uOutCurrencyID // Next is not XRP
&& uOutIssuerID != uReceiverID // Out issuer is not receiver
&& (pnPrv.uCurrencyID != uOutCurrencyID // Previous will be an offer.
|| pnPrv.uAccountID != uOutIssuerID)) // Need the implied issuer.
{
// Add implied account.
WriteLog (lsDEBUG, RippleCalc) << boost::str (boost::format ("setExpanded: receiver implied: account=%s currency=%s issuer=%s")
% RippleAddress::createHumanAccountID (uOutIssuerID)
% STAmount::createHumanCurrency (uOutCurrencyID)
% RippleAddress::createHumanAccountID (uOutIssuerID));
terStatus = pushNode (
!!uOutCurrencyID
? STPathElement::typeAccount | STPathElement::typeCurrency | STPathElement::typeIssuer
: STPathElement::typeAccount | STPathElement::typeCurrency,
uOutIssuerID,
uOutCurrencyID,
uOutIssuerID);
}
if (tesSUCCESS == terStatus)
{
// Create receiver node.
// Last node is always an account.
terStatus = pushNode (
!!uOutCurrencyID
? STPathElement::typeAccount | STPathElement::typeCurrency | STPathElement::typeIssuer
: STPathElement::typeAccount | STPathElement::typeCurrency,
uReceiverID, // Receive to output
uOutCurrencyID, // Desired currency
uReceiverID);
}
if (tesSUCCESS == terStatus)
{
// Look for first mention of source in nodes and detect loops.
// Note: The output is not allowed to be a source.
const unsigned int uNodes = vpnNodes.size ();
for (unsigned int uNode = 0; tesSUCCESS == terStatus && uNode != uNodes; ++uNode)
{
const PaymentNode& pnCur = vpnNodes[uNode];
if (!umForward.insert (std::make_pair (boost::make_tuple (pnCur.uAccountID, pnCur.uCurrencyID, pnCur.uIssuerID), uNode)).second)
{
// Failed to insert. Have a loop.
WriteLog (lsDEBUG, RippleCalc) << boost::str (boost::format ("setExpanded: loop detected: %s")
% getJson ());
terStatus = temBAD_PATH_LOOP;
}
}
}
WriteLog (lsDEBUG, RippleCalc) << boost::str (boost::format ("setExpanded: in=%s/%s out=%s/%s %s")
% STAmount::createHumanCurrency (uMaxCurrencyID)
% RippleAddress::createHumanAccountID (uMaxIssuerID)
% STAmount::createHumanCurrency (uOutCurrencyID)
% RippleAddress::createHumanAccountID (uOutIssuerID)
% getJson ());
}
// Set to a canonical path.
// - Remove extra elements
// - Assumes path is expanded.
//
// We do canonicalization to:
// - Prevent waste in the ledger.
// - Allow longer paths to be specified than would otherwise be allowed.
//
// Optimization theory:
// - Can omit elements that the expansion routine derives.
// - Can pack some elements into other elements.
//
// Rules:
// - SendMax if not specified, defaults currency to send and if not sending XRP defaults issuer to sender.
// - All paths start with the sender account.
// - Currency and issuer is from SendMax.
// - All paths end with the destination account.
//
// Optimization:
// - An XRP output implies an offer node or destination node is next.
// - A change in currency implies an offer node.
// - A change in issuer...
void PathState::setCanonical (
const PathState& psExpanded
)
{
assert (false);
saInAct = psExpanded.saInAct;
saOutAct = psExpanded.saOutAct;
const uint160 uMaxCurrencyID = saInAct.getCurrency ();
const uint160 uMaxIssuerID = saInAct.getIssuer ();
const uint160 uOutCurrencyID = saOutAct.getCurrency ();
const uint160 uOutIssuerID = saOutAct.getIssuer ();
unsigned int uNode = 0;
unsigned int uEnd = psExpanded.vpnNodes.size (); // The node, indexed by 0, not to include.
uint160 uDstAccountID = psExpanded.vpnNodes[uEnd].uAccountID; // FIXME: This can't be right
uint160 uAccountID = psExpanded.vpnNodes[0].uAccountID;
uint160 uCurrencyID = uMaxCurrencyID;
uint160 uIssuerID = uMaxIssuerID;
// Node 0 is a composite of the sending account and saInAct.
++uNode; // skip node 0
// Last node is implied: Always skip last node
--uEnd; // skip last node
// saInAct
// - currency is always the same as vpnNodes[0].
#if 1
if (uNode != uEnd && uMaxIssuerID != uAccountID)
{
// saInAct issuer is not the sender. This forces an implied node.
// WriteLog (lsDEBUG, RippleCalc) << boost::str(boost::format("setCanonical: in diff: uNode=%d uEnd=%d") % uNode % uEnd);
// skip node 1
uIssuerID = psExpanded.vpnNodes[uNode].uIssuerID;
++uNode;
}
#else
if (uNode != uEnd)
{
// Have another node
bool bKeep = false;
if (uMaxIssuerID != uAccountID)
{
}
if (uMaxCurrencyID) // Not sending XRP.
{
// Node 1 must be an account.
if (uMaxIssuerID != uAccountID)
{
// Node 1 is required to specify issuer.
bKeep = true;
}
else
{
// Node 1 must be an account
}
}
else
{
// Node 1 must be an order book.
bKeep = true;
}
if (bKeep)
{
uCurrencyID = psExpanded.vpnNodes[uNode].uCurrencyID;
uIssuerID = psExpanded.vpnNodes[uNode].uIssuerID;
++uNode; // Keep it.
}
}
#endif
if (uNode != uEnd && !!uOutCurrencyID && uOutIssuerID != uDstAccountID)
{
// WriteLog (lsDEBUG, RippleCalc) << boost::str(boost::format("setCanonical: out diff: uNode=%d uEnd=%d") % uNode % uEnd);
// The next to last node is saOutAct if an issuer different from receiver is supplied.
// The next to last node can be implied.
--uEnd;
}
const PaymentNode& pnEnd = psExpanded.vpnNodes[uEnd];
if (uNode != uEnd
&& !pnEnd.uAccountID && pnEnd.uCurrencyID == uOutCurrencyID && pnEnd.uIssuerID == uOutIssuerID)
{
// The current end node is an offer converting to saOutAct's currency and issuer and can be implied.
// WriteLog (lsDEBUG, RippleCalc) << boost::str(boost::format("setCanonical: out offer: uNode=%d uEnd=%d") % uNode % uEnd);
--uEnd;
}
// Do not include uEnd.
for (; uNode != uEnd; ++uNode)
{
// WriteLog (lsDEBUG, RippleCalc) << boost::str(boost::format("setCanonical: loop: uNode=%d uEnd=%d") % uNode % uEnd);
const PaymentNode& pnPrv = psExpanded.vpnNodes[uNode - 1];
const PaymentNode& pnCur = psExpanded.vpnNodes[uNode];
const PaymentNode& pnNxt = psExpanded.vpnNodes[uNode + 1];
const bool bCurAccount = isSetBit (pnCur.uFlags, STPathElement::typeAccount);
bool bSkip = false;
if (bCurAccount)
{
// Currently at an account.
// Output is non-XRP and issuer is account.
if (!!pnCur.uCurrencyID && pnCur.uIssuerID == pnCur.uAccountID)
{
// Account issues itself.
// XXX Not good enough. Previous account must mention it.
bSkip = true;
}
}
else
{
// Currently at an offer.
const bool bPrvAccount = isSetBit (pnPrv.uFlags, STPathElement::typeAccount);
const bool bNxtAccount = isSetBit (pnNxt.uFlags, STPathElement::typeAccount);
if (bPrvAccount && bNxtAccount // Offer surrounded by accounts.
&& pnPrv.uCurrencyID != pnNxt.uCurrencyID)
{
// Offer can be implied by currency change.
// XXX What about issuer?
bSkip = true;
}
}
if (!bSkip)
{
// Copy node
PaymentNode pnNew;
bool bSetAccount = bCurAccount;
bool bSetCurrency = uCurrencyID != pnCur.uCurrencyID;
// XXX What if we need the next account because we want to skip it?
bool bSetIssuer = !uCurrencyID && uIssuerID != pnCur.uIssuerID;
pnNew.uFlags = (bSetAccount ? STPathElement::typeAccount : 0)
| (bSetCurrency ? STPathElement::typeCurrency : 0)
| (bSetIssuer ? STPathElement::typeIssuer : 0);
if (bSetAccount)
pnNew.uAccountID = pnCur.uAccountID;
if (bSetCurrency)
{
pnNew.uCurrencyID = pnCur.uCurrencyID;
uCurrencyID = pnNew.uCurrencyID;
}
if (bSetIssuer)
pnNew.uIssuerID = pnCur.uIssuerID;
// XXX ^^^ What about setting uIssuerID?
if (bSetCurrency && !uCurrencyID)
uIssuerID.zero ();
vpnNodes.push_back (pnNew);
}
}
WriteLog (lsDEBUG, RippleCalc) << boost::str (boost::format ("setCanonical: in=%s/%s out=%s/%s %s")
% STAmount::createHumanCurrency (uMaxCurrencyID)
% RippleAddress::createHumanAccountID (uMaxIssuerID)
% STAmount::createHumanCurrency (uOutCurrencyID)
% RippleAddress::createHumanAccountID (uOutIssuerID)
% getJson ());
}
// Build a canonicalized STPathSet from a vector of PathStates.
void RippleCalc::setCanonical (STPathSet& spsDst, const std::vector<PathState::pointer>& vpsExpanded, bool bKeepDefault)
{
// WriteLog (lsDEBUG, RippleCalc) << boost::str(boost::format("SET: setCanonical> %d") % vpsExpanded.size());
BOOST_FOREACH (PathState::ref pspExpanded, vpsExpanded)
{
// Obvious defaults have 2 nodes when expanded.
if (bKeepDefault || 2 != pspExpanded->vpnNodes.size ())
{
PathState psCanonical (*pspExpanded, false); // Doesn't copy.
// WriteLog (lsDEBUG, RippleCalc) << boost::str(boost::format("SET: setCanonical: %d %d %s") % bKeepDirect % pspExpanded->vpnNodes.size() % pspExpanded->getJson());
psCanonical.setCanonical (*pspExpanded); // Convert.
// Non-obvious defaults have 0 nodes when canonicalized.
if (bKeepDefault || psCanonical.vpnNodes.size ())
{
STPath spCanonical;
BOOST_FOREACH (const PaymentNode & pnElem, psCanonical.vpnNodes)
{
STPathElement speElem (pnElem.uFlags, pnElem.uAccountID, pnElem.uCurrencyID, pnElem.uIssuerID);
spCanonical.addElement (speElem);
}
spsDst.addPath (spCanonical);
}
}
}
// WriteLog (lsDEBUG, RippleCalc) << boost::str(boost::format("SET: setCanonical< %d") % spsDst.size());
}
// This is for debugging not end users. Output names can be changed without warning.
Json::Value PathState::getJson () const
{
Json::Value jvPathState (Json::objectValue);
Json::Value jvNodes (Json::arrayValue);
BOOST_FOREACH (const PaymentNode & pnNode, vpnNodes)
{
jvNodes.append (pnNode.getJson ());
}
jvPathState["status"] = terStatus;
jvPathState["index"] = mIndex;
jvPathState["nodes"] = jvNodes;
if (saInReq)
jvPathState["in_req"] = saInReq.getJson (0);
if (saInAct)
jvPathState["in_act"] = saInAct.getJson (0);
if (saInPass)
jvPathState["in_pass"] = saInPass.getJson (0);
if (saOutReq)
jvPathState["out_req"] = saOutReq.getJson (0);
if (saOutAct)
jvPathState["out_act"] = saOutAct.getJson (0);
if (saOutPass)
jvPathState["out_pass"] = saOutPass.getJson (0);
if (uQuality)
jvPathState["uQuality"] = boost::str (boost::format ("%d") % uQuality);
return jvPathState;
}
//
// RippleCalc implementation
//
// If needed, advance to next funded offer.
// - Automatically advances to first offer.
// --> bEntryAdvance: true, to advance to next entry. false, recalculate.
@@ -835,8 +17,8 @@ TER RippleCalc::calcNodeAdvance (
const bool bMultiQuality,
const bool bReverse)
{
PaymentNode& pnPrv = psCur.vpnNodes[uNode - 1];
PaymentNode& pnCur = psCur.vpnNodes[uNode];
PathState::Node& pnPrv = psCur.vpnNodes[uNode - 1];
PathState::Node& pnCur = psCur.vpnNodes[uNode];
const uint160& uPrvCurrencyID = pnPrv.uCurrencyID;
const uint160& uPrvIssuerID = pnPrv.uIssuerID;
@@ -1144,8 +326,8 @@ TER RippleCalc::calcNodeDeliverRev (
{
TER terResult = tesSUCCESS;
PaymentNode& pnPrv = psCur.vpnNodes[uNode - 1];
PaymentNode& pnCur = psCur.vpnNodes[uNode];
PathState::Node& pnPrv = psCur.vpnNodes[uNode - 1];
PathState::Node& pnCur = psCur.vpnNodes[uNode];
const uint160& uCurIssuerID = pnCur.uIssuerID;
const uint160& uPrvAccountID = pnPrv.uAccountID;
@@ -1424,9 +606,9 @@ TER RippleCalc::calcNodeDeliverFwd (
{
TER terResult = tesSUCCESS;
PaymentNode& pnPrv = psCur.vpnNodes[uNode - 1];
PaymentNode& pnCur = psCur.vpnNodes[uNode];
PaymentNode& pnNxt = psCur.vpnNodes[uNode + 1];
PathState::Node& pnPrv = psCur.vpnNodes[uNode - 1];
PathState::Node& pnCur = psCur.vpnNodes[uNode];
PathState::Node& pnNxt = psCur.vpnNodes[uNode + 1];
const uint160& uNxtAccountID = pnNxt.uAccountID;
const uint160& uCurCurrencyID = pnCur.uCurrencyID;
@@ -1695,8 +877,8 @@ TER RippleCalc::calcNodeOfferRev (
{
TER terResult;
PaymentNode& pnCur = psCur.vpnNodes[uNode];
PaymentNode& pnNxt = psCur.vpnNodes[uNode + 1];
PathState::Node& pnCur = psCur.vpnNodes [uNode];
PathState::Node& pnNxt = psCur.vpnNodes [uNode + 1];
if (!!pnNxt.uAccountID)
{
@@ -1742,7 +924,7 @@ TER RippleCalc::calcNodeOfferFwd (
)
{
TER terResult;
PaymentNode& pnPrv = psCur.vpnNodes[uNode - 1];
PathState::Node& pnPrv = psCur.vpnNodes [uNode - 1];
if (!!pnPrv.uAccountID)
{
@@ -1899,9 +1081,9 @@ TER RippleCalc::calcNodeAccountRev (const unsigned int uNode, PathState& psCur,
uint64 uRateMax = 0;
PaymentNode& pnPrv = psCur.vpnNodes[uNode ? uNode - 1 : 0];
PaymentNode& pnCur = psCur.vpnNodes[uNode];
PaymentNode& pnNxt = psCur.vpnNodes[uNode == uLast ? uLast : uNode + 1];
PathState::Node& pnPrv = psCur.vpnNodes[uNode ? uNode - 1 : 0];
PathState::Node& pnCur = psCur.vpnNodes[uNode];
PathState::Node& pnNxt = psCur.vpnNodes[uNode == uLast ? uLast : uNode + 1];
// Current is allowed to redeem to next.
const bool bPrvAccount = !uNode || isSetBit (pnPrv.uFlags, STPathElement::typeAccount);
@@ -2257,14 +1439,14 @@ TER RippleCalc::calcNodeAccountFwd (
PathState& psCur,
const bool bMultiQuality)
{
TER terResult = tesSUCCESS;
const unsigned int uLast = psCur.vpnNodes.size () - 1;
TER terResult = tesSUCCESS;
const unsigned int uLast = psCur.vpnNodes.size () - 1;
uint64 uRateMax = 0;
uint64 uRateMax = 0;
PaymentNode& pnPrv = psCur.vpnNodes[uNode ? uNode - 1 : 0];
PaymentNode& pnCur = psCur.vpnNodes[uNode];
PaymentNode& pnNxt = psCur.vpnNodes[uNode == uLast ? uLast : uNode + 1];
PathState::Node& pnPrv = psCur.vpnNodes[uNode ? uNode - 1 : 0];
PathState::Node& pnCur = psCur.vpnNodes[uNode];
PathState::Node& pnNxt = psCur.vpnNodes[uNode == uLast ? uLast : uNode + 1];
const bool bPrvAccount = isSetBit (pnPrv.uFlags, STPathElement::typeAccount);
const bool bNxtAccount = isSetBit (pnNxt.uFlags, STPathElement::typeAccount);
@@ -2591,7 +1773,7 @@ TER RippleCalc::calcNodeAccountFwd (
TER RippleCalc::calcNodeFwd (const unsigned int uNode, PathState& psCur, const bool bMultiQuality)
{
const PaymentNode& pnCur = psCur.vpnNodes[uNode];
const PathState::Node& pnCur = psCur.vpnNodes[uNode];
const bool bCurAccount = isSetBit (pnCur.uFlags, STPathElement::typeAccount);
WriteLog (lsDEBUG, RippleCalc) << boost::str (boost::format ("calcNodeFwd> uNode=%d") % uNode);
@@ -2621,9 +1803,9 @@ TER RippleCalc::calcNodeFwd (const unsigned int uNode, PathState& psCur, const b
// <-> [0]saWanted.mAmount : --> limit, <-- actual
TER RippleCalc::calcNodeRev (const unsigned int uNode, PathState& psCur, const bool bMultiQuality)
{
PaymentNode& pnCur = psCur.vpnNodes[uNode];
const bool bCurAccount = isSetBit (pnCur.uFlags, STPathElement::typeAccount);
TER terResult;
PathState::Node& pnCur = psCur.vpnNodes[uNode];
bool const bCurAccount = isSetBit (pnCur.uFlags, STPathElement::typeAccount);
TER terResult;
// Do current node reverse.
const uint160& uCurIssuerID = pnCur.uIssuerID;
@@ -2685,7 +1867,7 @@ void RippleCalc::pathNext (PathState::ref psrCur, const bool bMultiQuality, cons
for (unsigned int uIndex = psrCur->vpnNodes.size (); uIndex--;)
{
PaymentNode& pnCur = psrCur->vpnNodes[uIndex];
PathState::Node& pnCur = psrCur->vpnNodes[uIndex];
pnCur.saRevRedeem.zero ();
pnCur.saRevIssue.zero ();
@@ -3081,7 +2263,7 @@ TER RippleCalc::rippleCalc (
// <-- terResult : tesSUCCESS = no error and if !bAllowPartial complelely satisfied wanted.
// <-> usOffersDeleteAlways:
// <-> usOffersDeleteOnSuccess:
TER calcOfferFill (PaymentNode& pnSrc, PaymentNode& pnDst, bool bAllowPartial)
TER calcOfferFill (Node& pnSrc, Node& pnDst, bool bAllowPartial)
{
TER terResult;

View File

@@ -0,0 +1,78 @@
#ifndef RIPPLE_RIPPLECALC_H
#define RIPPLE_RIPPLECALC_H
// VFALCO TODO What's the difference between a RippleCalc versus Pathfinder?
// Or a RippleState versus PathState?
//
class RippleCalc
{
public:
// First time working in reverse a funding source was mentioned. Source may only be used there.
curIssuerNode mumSource; // Map of currency, issuer to node index.
// If the transaction fails to meet some constraint, still need to delete unfunded offers.
boost::unordered_set<uint256> musUnfundedFound; // Offers that were found unfunded.
void pathNext (PathState::ref psrCur, const bool bMultiQuality, const LedgerEntrySet& lesCheckpoint, LedgerEntrySet& lesCurrent);
TER calcNode (const unsigned int uNode, PathState& psCur, const bool bMultiQuality);
TER calcNodeRev (const unsigned int uNode, PathState& psCur, const bool bMultiQuality);
TER calcNodeFwd (const unsigned int uNode, PathState& psCur, const bool bMultiQuality);
TER calcNodeOfferRev (const unsigned int uNode, PathState& psCur, const bool bMultiQuality);
TER calcNodeOfferFwd (const unsigned int uNode, PathState& psCur, const bool bMultiQuality);
TER calcNodeAccountRev (const unsigned int uNode, PathState& psCur, const bool bMultiQuality);
TER calcNodeAccountFwd (const unsigned int uNode, PathState& psCur, const bool bMultiQuality);
TER calcNodeAdvance (const unsigned int uNode, PathState& psCur, const bool bMultiQuality, const bool bReverse);
TER calcNodeDeliverRev (
const unsigned int uNode,
PathState& psCur,
const bool bMultiQuality,
const uint160& uOutAccountID,
const STAmount& saOutReq,
STAmount& saOutAct);
TER calcNodeDeliverFwd (
const unsigned int uNode,
PathState& psCur,
const bool bMultiQuality,
const uint160& uInAccountID,
const STAmount& saInReq,
STAmount& saInAct,
STAmount& saInFees);
void calcNodeRipple (const uint32 uQualityIn, const uint32 uQualityOut,
const STAmount& saPrvReq, const STAmount& saCurReq,
STAmount& saPrvAct, STAmount& saCurAct,
uint64& uRateMax);
RippleCalc (LedgerEntrySet& lesNodes, const bool bOpenLedger)
: lesActive (lesNodes), mOpenLedger (bOpenLedger)
{
;
}
static TER rippleCalc (
LedgerEntrySet& lesActive,
STAmount& saMaxAmountAct,
STAmount& saDstAmountAct,
std::vector<PathState::pointer>& vpsExpanded,
const STAmount& saDstAmountReq,
const STAmount& saMaxAmountReq,
const uint160& uDstAccountID,
const uint160& uSrcAccountID,
const STPathSet& spsPaths,
const bool bPartialPayment,
const bool bLimitQuality,
const bool bNoRippleDirect,
const bool bStandAlone, // --> True, not to affect accounts.
const bool bOpenLedger = true // --> What kind of errors to return.
);
static void setCanonical (STPathSet& spsDst, const std::vector<PathState::pointer>& vpsExpanded, bool bKeepDefault);
protected:
LedgerEntrySet& lesActive;
bool mOpenLedger;
};
#endif
// vim:ts=4

View File

@@ -0,0 +1,13 @@
AccountItems& RippleLineCache::getRippleLines (const uint160& accountID)
{
boost::mutex::scoped_lock sl (mLock);
boost::unordered_map <uint160, AccountItems::pointer>::iterator it = mRLMap.find (accountID);
if (it == mRLMap.end ())
it = mRLMap.insert (std::make_pair (accountID, boost::make_shared<AccountItems>
(boost::cref (accountID), boost::cref (mLedger), AccountItem::pointer (new RippleState ())))).first;
return *it->second;
}

View File

@@ -0,0 +1,31 @@
#ifndef RIPPLE_RIPPLELINECACHE_H
#define RIPPLE_RIPPLELINECACHE_H
// Used by Pathfinder
class RippleLineCache
{
public:
typedef boost::shared_ptr <RippleLineCache> pointer;
typedef pointer const& ref;
explicit RippleLineCache (Ledger::ref l)
: mLedger (l)
{
}
Ledger::ref getLedger () // VFALCO TODO const?
{
return mLedger;
}
AccountItems& getRippleLines (const uint160& accountID);
private:
boost::mutex mLock;
Ledger::pointer mLedger;
boost::unordered_map <uint160, AccountItems::pointer> mRLMap;
};
#endif

View File

@@ -1,5 +1,5 @@
#ifndef __RIPPLESTATE__
#define __RIPPLESTATE__
#ifndef RIPPLE_RIPPLESTATE_H
#define RIPPLE_RIPPLESTATE_H
//
// A ripple line's state.
@@ -9,7 +9,89 @@
class RippleState : public AccountItem
{
public:
typedef boost::shared_ptr<RippleState> pointer;
typedef boost::shared_ptr <RippleState> pointer;
public:
RippleState () { }
virtual ~RippleState () { }
AccountItem::pointer makeItem (const uint160& accountID, SerializedLedgerEntry::ref ledgerEntry);
LedgerEntryType getType ()
{
return ltRIPPLE_STATE;
}
void setViewAccount (const uint160& accountID);
const uint160& getAccountID () const
{
return mViewLowest ? mLowID : mHighID;
}
const uint160& getAccountIDPeer () const
{
return !mViewLowest ? mLowID : mHighID;
}
// True, Provided auth to peer.
bool getAuth () const
{
return isSetBit (mFlags, mViewLowest ? lsfLowAuth : lsfHighAuth);
}
bool getAuthPeer () const
{
return isSetBit (mFlags, !mViewLowest ? lsfLowAuth : lsfHighAuth);
}
const STAmount& getBalance () const
{
return mBalance;
}
const STAmount& getLimit () const
{
return mViewLowest ? mLowLimit : mHighLimit;
}
const STAmount& getLimitPeer () const
{
return !mViewLowest ? mLowLimit : mHighLimit;
}
uint32 getQualityIn () const
{
return ((uint32) (mViewLowest ? mLowQualityIn : mHighQualityIn));
}
uint32 getQualityOut () const
{
return ((uint32) (mViewLowest ? mLowQualityOut : mHighQualityOut));
}
SerializedLedgerEntry::pointer getSLE ()
{
return mLedgerEntry;
}
const SerializedLedgerEntry& peekSLE () const
{
return *mLedgerEntry;
}
SerializedLedgerEntry& peekSLE ()
{
return *mLedgerEntry;
}
Json::Value getJson (int);
Blob getRaw () const;
private:
explicit RippleState (SerializedLedgerEntry::ref ledgerEntry); // For accounts in a ledger
private:
bool mValid;
@@ -29,76 +111,6 @@ private:
uint64 mHighQualityOut;
STAmount mBalance;
RippleState (SerializedLedgerEntry::ref ledgerEntry); // For accounts in a ledger
public:
RippleState () { }
virtual ~RippleState () {}
AccountItem::pointer makeItem (const uint160& accountID, SerializedLedgerEntry::ref ledgerEntry);
LedgerEntryType getType ()
{
return (ltRIPPLE_STATE);
}
void setViewAccount (const uint160& accountID);
const uint160& getAccountID () const
{
return mViewLowest ? mLowID : mHighID;
}
const uint160& getAccountIDPeer () const
{
return !mViewLowest ? mLowID : mHighID;
}
// True, Provided auth to peer.
bool getAuth () const
{
return isSetBit (mFlags, mViewLowest ? lsfLowAuth : lsfHighAuth);
}
bool getAuthPeer () const
{
return isSetBit (mFlags, !mViewLowest ? lsfLowAuth : lsfHighAuth);
}
const STAmount& getBalance () const
{
return mBalance;
}
const STAmount& getLimit () const
{
return mViewLowest ? mLowLimit : mHighLimit;
}
const STAmount& getLimitPeer () const
{
return !mViewLowest ? mLowLimit : mHighLimit;
}
uint32 getQualityIn () const
{
return ((uint32) (mViewLowest ? mLowQualityIn : mHighQualityIn));
}
uint32 getQualityOut () const
{
return ((uint32) (mViewLowest ? mLowQualityOut : mHighQualityOut));
}
SerializedLedgerEntry::pointer getSLE ()
{
return mLedgerEntry;
}
const SerializedLedgerEntry& peekSLE () const
{
return *mLedgerEntry;
}
SerializedLedgerEntry& peekSLE ()
{
return *mLedgerEntry;
}
Json::Value getJson (int);
Blob getRaw () const;
};
#endif
// vim:ts=4

View File

@@ -45,7 +45,7 @@ bool ConsensusTransSetSF::haveNode (const SHAMapNode& id, uint256 const& nodeHas
// this is a transaction, and we have it
WriteLog (lsDEBUG, TransactionAcquire) << "Node in our acquiring TX set is TXN we have";
Serializer s;
s.add32 (sHP_TransactionID);
s.add32 (HashPrefix::transactionID);
txn->getSTransaction ()->add (s, true);
assert (s.getSHA512Half () == nodeHash);
nodeData = s.peekData ();

View File

@@ -44,7 +44,7 @@ SHAMapTreeNode::SHAMapTreeNode (const SHAMapNode& id, Blob const& rawNode, uint3
if (type == 0)
{
// transaction
mItem = boost::make_shared<SHAMapItem> (s.getPrefixHash (sHP_TransactionID), s.peekData ());
mItem = boost::make_shared<SHAMapItem> (s.getPrefixHash (HashPrefix::transactionID), s.peekData ());
mType = tnTRANSACTION_NM;
}
else if (type == 1)
@@ -131,12 +131,12 @@ SHAMapTreeNode::SHAMapTreeNode (const SHAMapNode& id, Blob const& rawNode, uint3
prefix |= rawNode[3];
Serializer s (rawNode.begin () + 4, rawNode.end ());
if (prefix == sHP_TransactionID)
if (prefix == HashPrefix::transactionID)
{
mItem = boost::make_shared<SHAMapItem> (Serializer::getSHA512Half (rawNode), s.peekData ());
mType = tnTRANSACTION_NM;
}
else if (prefix == sHP_LeafNode)
else if (prefix == HashPrefix::leafNode)
{
if (s.getLength () < 32)
throw std::runtime_error ("short PLN node");
@@ -154,7 +154,7 @@ SHAMapTreeNode::SHAMapTreeNode (const SHAMapNode& id, Blob const& rawNode, uint3
mItem = boost::make_shared<SHAMapItem> (u, s.peekData ());
mType = tnACCOUNT_STATE;
}
else if (prefix == sHP_InnerNode)
else if (prefix == HashPrefix::innerNode)
{
if (s.getLength () != 512)
throw std::runtime_error ("invalid PIN node");
@@ -169,7 +169,7 @@ SHAMapTreeNode::SHAMapTreeNode (const SHAMapNode& id, Blob const& rawNode, uint3
mType = tnINNER;
}
else if (prefix == sHP_TransactionNode)
else if (prefix == HashPrefix::txNode)
{
// transaction with metadata
if (s.getLength () < 32)
@@ -214,10 +214,10 @@ bool SHAMapTreeNode::updateHash ()
{
if (mIsBranch != 0)
{
nh = Serializer::getPrefixHash (sHP_InnerNode, reinterpret_cast<unsigned char*> (mHashes), sizeof (mHashes));
nh = Serializer::getPrefixHash (HashPrefix::innerNode, reinterpret_cast<unsigned char*> (mHashes), sizeof (mHashes));
#ifdef PARANOID
Serializer s;
s.add32 (sHP_InnerNode);
s.add32 (HashPrefix::innerNode);
for (int i = 0; i < 16; ++i)
s.add256 (mHashes[i]);
@@ -230,12 +230,12 @@ bool SHAMapTreeNode::updateHash ()
}
else if (mType == tnTRANSACTION_NM)
{
nh = Serializer::getPrefixHash (sHP_TransactionID, mItem->peekData ());
nh = Serializer::getPrefixHash (HashPrefix::transactionID, mItem->peekData ());
}
else if (mType == tnACCOUNT_STATE)
{
Serializer s (mItem->peekSerializer ().getDataLength () + (256 + 32) / 8);
s.add32 (sHP_LeafNode);
s.add32 (HashPrefix::leafNode);
s.addRaw (mItem->peekData ());
s.add256 (mItem->getTag ());
nh = s.getSHA512Half ();
@@ -243,7 +243,7 @@ bool SHAMapTreeNode::updateHash ()
else if (mType == tnTRANSACTION_MD)
{
Serializer s (mItem->peekSerializer ().getDataLength () + (256 + 32) / 8);
s.add32 (sHP_TransactionNode);
s.add32 (HashPrefix::txNode);
s.addRaw (mItem->peekData ());
s.add256 (mItem->getTag ());
nh = s.getSHA512Half ();
@@ -275,7 +275,7 @@ void SHAMapTreeNode::addRaw (Serializer& s, SHANodeFormat format)
if (format == snfPREFIX)
{
s.add32 (sHP_InnerNode);
s.add32 (HashPrefix::innerNode);
for (int i = 0; i < 16; ++i)
s.add256 (mHashes[i]);
@@ -307,7 +307,7 @@ void SHAMapTreeNode::addRaw (Serializer& s, SHANodeFormat format)
{
if (format == snfPREFIX)
{
s.add32 (sHP_LeafNode);
s.add32 (HashPrefix::leafNode);
s.addRaw (mItem->peekData ());
s.add256 (mItem->getTag ());
}
@@ -322,7 +322,7 @@ void SHAMapTreeNode::addRaw (Serializer& s, SHANodeFormat format)
{
if (format == snfPREFIX)
{
s.add32 (sHP_TransactionID);
s.add32 (HashPrefix::transactionID);
s.addRaw (mItem->peekData ());
}
else
@@ -335,7 +335,7 @@ void SHAMapTreeNode::addRaw (Serializer& s, SHANodeFormat format)
{
if (format == snfPREFIX)
{
s.add32 (sHP_TransactionNode);
s.add32 (HashPrefix::txNode);
s.addRaw (mItem->peekData ());
s.add256 (mItem->getTag ());
}

View File

@@ -3,7 +3,21 @@
DEFINE_INSTANCE (SerializedLedgerEntry);
// VFALCO TODO rename this to SerializedLedger?
// 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, private IS_INSTANCE (SerializedLedgerEntry)
{
public:

View File

@@ -3,10 +3,13 @@ SETUP_LOG (SerializedTransaction)
DECLARE_INSTANCE (SerializedTransaction);
SerializedTransaction::SerializedTransaction (TransactionType type) : STObject (sfTransaction), mType (type),
mSigGood (false), mSigBad (false)
SerializedTransaction::SerializedTransaction (TransactionType type)
: STObject (sfTransaction)
, mType (type)
, mSigGood (false)
, mSigBad (false)
{
mFormat = TransactionFormat::getTxnFormat (type);
mFormat = TxFormats::getInstance ().findByType (type);
if (mFormat == NULL)
{
@@ -15,14 +18,17 @@ SerializedTransaction::SerializedTransaction (TransactionType type) : STObject (
}
set (mFormat->elements);
setFieldU16 (sfTransactionType, mFormat->t_type);
setFieldU16 (sfTransactionType, mFormat->getType ());
}
SerializedTransaction::SerializedTransaction (const STObject& object) : STObject (object),
mSigGood (false), mSigBad (false)
SerializedTransaction::SerializedTransaction (STObject const& object)
: STObject (object)
, mSigGood (false)
, mSigBad (false)
{
mType = static_cast<TransactionType> (getFieldU16 (sfTransactionType));
mFormat = TransactionFormat::getTxnFormat (mType);
mType = static_cast <TransactionType> (getFieldU16 (sfTransactionType));
mFormat = TxFormats::getInstance ().findByType (mType);
if (!mFormat)
{
@@ -41,7 +47,7 @@ SerializedTransaction::SerializedTransaction (SerializerIterator& sit) : STObjec
{
int length = sit.getBytesLeft ();
if ((length < TransactionMinLen) || (length > TransactionMaxLen))
if ((length < Protocol::txMinSizeBytes) || (length > Protocol::txMaxSizeBytes))
{
Log (lsERROR) << "Transaction has invalid length: " << length;
throw std::runtime_error ("Transaction length invalid");
@@ -50,7 +56,7 @@ SerializedTransaction::SerializedTransaction (SerializerIterator& sit) : STObjec
set (sit);
mType = static_cast<TransactionType> (getFieldU16 (sfTransactionType));
mFormat = TransactionFormat::getTxnFormat (mType);
mFormat = TxFormats::getInstance ().findByType (mType);
if (!mFormat)
{
@@ -141,7 +147,7 @@ uint256 SerializedTransaction::getSigningHash () const
uint256 SerializedTransaction::getTransactionID () const
{
// perhaps we should cache this
return getHash (sHP_TransactionID);
return getHash (HashPrefix::transactionID);
}
Blob SerializedTransaction::getSignature () const

View File

@@ -64,7 +64,7 @@ public:
void setSourceAccount (const RippleAddress & naSource);
std::string getTransactionType () const
{
return mFormat->t_name;
return mFormat->getName ();
}
uint32 getSequence () const
@@ -120,7 +120,7 @@ public:
private:
TransactionType mType;
const TransactionFormat* mFormat;
const TxFormat* mFormat;
SerializedTransaction* duplicate () const
{