mirror of
https://github.com/XRPLF/rippled.git
synced 2025-11-28 23:15:52 +00:00
Tidy up TxFormat and create TxFormats, TxFlags
This commit is contained in:
@@ -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
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
59
modules/ripple_data/protocol/ripple_HashPrefix.h
Normal file
59
modules/ripple_data/protocol/ripple_HashPrefix.h
Normal 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
|
||||
@@ -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
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
51
modules/ripple_data/protocol/ripple_TxFlags.h
Normal file
51
modules/ripple_data/protocol/ripple_TxFlags.h
Normal 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
|
||||
@@ -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
|
||||
70
modules/ripple_data/protocol/ripple_TxFormat.h
Normal file
70
modules/ripple_data/protocol/ripple_TxFormat.h
Normal 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
|
||||
49
modules/ripple_data/protocol/ripple_TxFormats.cpp
Normal file
49
modules/ripple_data/protocol/ripple_TxFormats.cpp
Normal 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 ()
|
||||
{
|
||||
}
|
||||
|
||||
40
modules/ripple_data/protocol/ripple_TxFormats.h
Normal file
40
modules/ripple_data/protocol/ripple_TxFormats.h
Normal 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
|
||||
@@ -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;
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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" />
|
||||
|
||||
@@ -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" />
|
||||
|
||||
@@ -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.";
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
|
||||
#include "HTTPRequest.h"
|
||||
#include "RPCHandler.h"
|
||||
#include "LoadManager.h"
|
||||
|
||||
class RPCServer : public boost::enable_shared_from_this<RPCServer>
|
||||
{
|
||||
|
||||
@@ -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
|
||||
@@ -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 ()
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
|
||||
|
||||
// VFALCO TODO Wrap this up in something neater. Replace NULL with nullptr
|
||||
IApplication* theApp = NULL;
|
||||
|
||||
|
||||
class Application;
|
||||
|
||||
SETUP_LOG (Application)
|
||||
|
||||
@@ -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 ());
|
||||
|
||||
@@ -108,4 +108,3 @@ public:
|
||||
extern IApplication* theApp;
|
||||
|
||||
#endif
|
||||
// vim:ts=4
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -3,6 +3,8 @@
|
||||
|
||||
// Monitors load levels and response times
|
||||
|
||||
// VFALCO TODO Rename this. Having both LoadManager and LoadMonitor is confusing.
|
||||
//
|
||||
class LoadMonitor
|
||||
{
|
||||
public:
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
787
src/cpp/ripple/ripple_PathState.cpp
Normal file
787
src/cpp/ripple/ripple_PathState.cpp
Normal 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;
|
||||
}
|
||||
|
||||
158
src/cpp/ripple/ripple_PathState.h
Normal file
158
src/cpp/ripple/ripple_PathState.h
Normal 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
|
||||
@@ -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);
|
||||
@@ -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
|
||||
@@ -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;
|
||||
|
||||
78
src/cpp/ripple/ripple_RippleCalc.h
Normal file
78
src/cpp/ripple/ripple_RippleCalc.h
Normal 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
|
||||
13
src/cpp/ripple/ripple_RippleLineCache.cpp
Normal file
13
src/cpp/ripple/ripple_RippleLineCache.cpp
Normal 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;
|
||||
}
|
||||
31
src/cpp/ripple/ripple_RippleLineCache.h
Normal file
31
src/cpp/ripple/ripple_RippleLineCache.h
Normal 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
|
||||
@@ -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
|
||||
@@ -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 ();
|
||||
|
||||
@@ -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 ());
|
||||
}
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user