diff --git a/RefactoringNotes.txt b/RefactoringNotes.txt index 8c76d2d960..c0239bd81c 100644 --- a/RefactoringNotes.txt +++ b/RefactoringNotes.txt @@ -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 + diff --git a/modules/ripple_client/ripple_client.cpp b/modules/ripple_client/ripple_client.cpp index ace0470f58..58afbe5a87 100644 --- a/modules/ripple_client/ripple_client.cpp +++ b/modules/ripple_client/ripple_client.cpp @@ -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" diff --git a/modules/ripple_data/protocol/ripple_HashPrefix.h b/modules/ripple_data/protocol/ripple_HashPrefix.h new file mode 100644 index 0000000000..073ba70799 --- /dev/null +++ b/modules/ripple_data/protocol/ripple_HashPrefix.h @@ -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 diff --git a/modules/ripple_data/protocol/ripple_ProtocolTypes.h b/modules/ripple_data/protocol/ripple_Protocol.h similarity index 64% rename from modules/ripple_data/protocol/ripple_ProtocolTypes.h rename to modules/ripple_data/protocol/ripple_Protocol.h index 31e66ecf95..17f0bc0c98 100644 --- a/modules/ripple_data/protocol/ripple_ProtocolTypes.h +++ b/modules/ripple_data/protocol/ripple_Protocol.h @@ -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 diff --git a/modules/ripple_data/protocol/ripple_SerializedObject.cpp b/modules/ripple_data/protocol/ripple_SerializedObject.cpp index d70128495f..c159941a90 100644 --- a/modules/ripple_data/protocol/ripple_SerializedObject.cpp +++ b/modules/ripple_data/protocol/ripple_SerializedObject.cpp @@ -1262,12 +1262,12 @@ UPTR_T 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 (f->t_type))); + data.push_back (new STUInt16 (field, static_cast (f->getType ()))); if (*name == sfGeneric) name = &sfTransaction; diff --git a/modules/ripple_data/protocol/ripple_SerializedTypes.cpp b/modules/ripple_data/protocol/ripple_SerializedTypes.cpp index c73cc122b9..6a2546f180 100644 --- a/modules/ripple_data/protocol/ripple_SerializedTypes.cpp +++ b/modules/ripple_data/protocol/ripple_SerializedTypes.cpp @@ -124,10 +124,10 @@ std::string STUInt16::getText () const if (getFName () == sfTransactionType) { - TransactionFormat* f = TransactionFormat::getTxnFormat (value); + TxFormat* f = TxFormats::getInstance ().findByType (static_cast (value)); if (f != NULL) - return f->t_name; + return f->getName (); } return boost::lexical_cast (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 (value)); if (f != NULL) - return f->t_name; + return f->getName (); } return value; diff --git a/modules/ripple_data/protocol/ripple_SerializedTypes.h b/modules/ripple_data/protocol/ripple_SerializedTypes.h index 3284aedb57..7d4a7c38a2 100644 --- a/modules/ripple_data/protocol/ripple_SerializedTypes.h +++ b/modules/ripple_data/protocol/ripple_SerializedTypes.h @@ -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: diff --git a/modules/ripple_data/protocol/ripple_TransactionFormat.h b/modules/ripple_data/protocol/ripple_TransactionFormat.h deleted file mode 100644 index 94de41913b..0000000000 --- a/modules/ripple_data/protocol/ripple_TransactionFormat.h +++ /dev/null @@ -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 byType; - static std::map 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 diff --git a/modules/ripple_data/protocol/ripple_TxFlags.h b/modules/ripple_data/protocol/ripple_TxFlags.h new file mode 100644 index 0000000000..13d8b265dc --- /dev/null +++ b/modules/ripple_data/protocol/ripple_TxFlags.h @@ -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 diff --git a/modules/ripple_data/protocol/ripple_TransactionFormat.cpp b/modules/ripple_data/protocol/ripple_TxFormat.cpp similarity index 75% rename from modules/ripple_data/protocol/ripple_TransactionFormat.cpp rename to modules/ripple_data/protocol/ripple_TxFormat.cpp index c8e198dfb7..dc1da150eb 100644 --- a/modules/ripple_data/protocol/ripple_TransactionFormat.cpp +++ b/modules/ripple_data/protocol/ripple_TxFormat.cpp @@ -1,10 +1,7 @@ -std::map TransactionFormat::byType; +// VFALCO TODO Find a way to not use macros. inline function? -std::map 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 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::iterator it = byType.find (static_cast (t)); - - if (it == byType.end ()) - return NULL; - - return it->second; -} - -TransactionFormat* TransactionFormat::getTxnFormat (int t) -{ - std::map::iterator it = byType.find ((t)); - - if (it == byType.end ()) - return NULL; - - return it->second; -} - -TransactionFormat* TransactionFormat::getTxnFormat (const std::string& t) -{ - std::map::iterator it = byName.find ((t)); - - if (it == byName.end ()) - return NULL; - - return it->second; -} - -// vim:ts=4 diff --git a/modules/ripple_data/protocol/ripple_TxFormat.h b/modules/ripple_data/protocol/ripple_TxFormat.h new file mode 100644 index 0000000000..f8e31abf9f --- /dev/null +++ b/modules/ripple_data/protocol/ripple_TxFormat.h @@ -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 diff --git a/modules/ripple_data/protocol/ripple_TxFormats.cpp b/modules/ripple_data/protocol/ripple_TxFormats.cpp new file mode 100644 index 0000000000..2d566965ab --- /dev/null +++ b/modules/ripple_data/protocol/ripple_TxFormats.cpp @@ -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 () +{ +} + diff --git a/modules/ripple_data/protocol/ripple_TxFormats.h b/modules/ripple_data/protocol/ripple_TxFormats.h new file mode 100644 index 0000000000..dfb2f4578d --- /dev/null +++ b/modules/ripple_data/protocol/ripple_TxFormats.h @@ -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 NameMap; + typedef std::map TypeMap; + + NameMap m_names; + TypeMap m_types; +}; + +#endif +// vim:ts=4 diff --git a/modules/ripple_data/ripple_data.cpp b/modules/ripple_data/ripple_data.cpp index a342d99d13..0ecb8758e4 100644 --- a/modules/ripple_data/ripple_data.cpp +++ b/modules/ripple_data/ripple_data.cpp @@ -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; diff --git a/modules/ripple_data/ripple_data.h b/modules/ripple_data/ripple_data.h index 0a00960b80..a531141d76 100644 --- a/modules/ripple_data/ripple_data.h +++ b/modules/ripple_data/ripple_data.h @@ -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" diff --git a/modules/ripple_main/ripple_main.cpp b/modules/ripple_main/ripple_main.cpp index 84ee602076..1a1a1688dd 100644 --- a/modules/ripple_main/ripple_main.cpp +++ b/modules/ripple_main/ripple_main.cpp @@ -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" diff --git a/newcoin.vcxproj b/newcoin.vcxproj index c0aae99431..b953d3db8d 100644 --- a/newcoin.vcxproj +++ b/newcoin.vcxproj @@ -353,7 +353,13 @@ true true - + + true + true + true + true + + true true true @@ -827,6 +833,12 @@ true true + + true + true + true + true + true true @@ -909,7 +921,7 @@ true true - + true true true @@ -945,13 +957,13 @@ true true - + true true true true - + true true true @@ -999,7 +1011,7 @@ true true - + true true true @@ -1027,13 +1039,19 @@ true true - + true true true true - + + true + true + true + true + + true true true @@ -1393,9 +1411,10 @@ + - + @@ -1404,7 +1423,9 @@ - + + + @@ -1751,7 +1772,6 @@ - @@ -1763,14 +1783,14 @@ - + - - + + @@ -1778,13 +1798,15 @@ - + - - + + + + diff --git a/newcoin.vcxproj.filters b/newcoin.vcxproj.filters index 32046244f9..c08f466d76 100644 --- a/newcoin.vcxproj.filters +++ b/newcoin.vcxproj.filters @@ -145,6 +145,9 @@ {8b88138b-e5bd-492b-bd34-012b9f43e544} + + {90a5527e-0de0-4d5f-a731-b6b196a013b5} + @@ -585,9 +588,6 @@ 1. Modules\ripple_basics\utility - - 1. Modules\ripple_main\_unfactored\main - 1. Modules\ripple_main\_unfactored\main @@ -651,24 +651,9 @@ 1. Modules\ripple_main\_unfactored\ledger - - 1. Modules\ripple_main\_unfactored\ledger - - - 1. Modules\ripple_main\_unfactored\ledger - 1. Modules\ripple_main\_unfactored\ledger - - 1. Modules\ripple_main\_unfactored\ledger - - - 1. Modules\ripple_main\_unfactored\ledger - - - 1. Modules\ripple_main\_unfactored\ledger - 1. Modules\ripple_data\crypto @@ -732,9 +717,6 @@ 1. Modules\ripple_data\protocol - - 1. Modules\ripple_data\protocol - 1. Modules\ripple_data\protocol @@ -798,12 +780,6 @@ 1. Modules\ripple_main\refactored - - 1. Modules\ripple_main\_unfactored\ledger - - - 1. Modules\ripple_main\_unfactored\main - 1. Modules\ripple_data\utility @@ -876,6 +852,42 @@ 1. Modules\ripple_main\refactored\consensus + + 1. Modules\ripple_main\refactored + + + 1. Modules\ripple_main\refactored + + + 1. Modules\ripple_main\refactored + + + 1. Modules\ripple_main\refactored + + + 1. Modules\ripple_main\refactored\pathing + + + 1. Modules\ripple_main\refactored\pathing + + + 1. Modules\ripple_main\refactored\pathing + + + 1. Modules\ripple_main\refactored\pathing + + + 1. Modules\ripple_main\refactored\pathing + + + 1. Modules\ripple_main\refactored\pathing + + + 1. Modules\ripple_data\protocol + + + 1. Modules\ripple_data\protocol + @@ -1193,9 +1205,6 @@ 1. Modules\ripple_main\_unfactored\contracts - - 1. Modules\ripple_main\_unfactored\types - 1. Modules\ripple_main\_unfactored\types @@ -1349,9 +1358,6 @@ 1. Modules\ripple_basics\utility - - 1. Modules\ripple_main\_unfactored\main - 1. Modules\ripple_main\_unfactored\main @@ -1415,24 +1421,9 @@ 1. Modules\ripple_main\_unfactored\ledger - - 1. Modules\ripple_main\_unfactored\ledger - - - 1. Modules\ripple_main\_unfactored\ledger - 1. Modules\ripple_main\_unfactored\ledger - - 1. Modules\ripple_main\_unfactored\ledger - - - 1. Modules\ripple_main\_unfactored\ledger - - - 1. Modules\ripple_main\_unfactored\ledger - 1. Modules\ripple_main\_unfactored\ledger @@ -1499,9 +1490,6 @@ 1. Modules\ripple_data\protocol - - 1. Modules\ripple_data\protocol - 1. Modules\ripple_data\protocol @@ -1544,9 +1532,6 @@ 1. Modules\ripple_basics\types - - 1. Modules\ripple_data\protocol - 1. Modules\ripple_main\refactored @@ -1568,12 +1553,6 @@ 1. Modules\ripple_main\refactored - - 1. Modules\ripple_main\_unfactored\ledger - - - 1. Modules\ripple_main\_unfactored\main - 1. Modules\ripple_data\utility @@ -1631,6 +1610,51 @@ 1. Modules\ripple_main\refactored\consensus + + 1. Modules\ripple_main\refactored + + + 1. Modules\ripple_main\refactored + + + 1. Modules\ripple_main\refactored + + + 1. Modules\ripple_main\refactored + + + 1. Modules\ripple_main\refactored\pathing + + + 1. Modules\ripple_main\refactored\pathing + + + 1. Modules\ripple_main\refactored\pathing + + + 1. Modules\ripple_main\refactored\pathing + + + 1. Modules\ripple_main\refactored\pathing + + + 1. Modules\ripple_main\refactored\pathing + + + 1. Modules\ripple_data\protocol + + + 1. Modules\ripple_data\protocol + + + 1. Modules\ripple_data\protocol + + + 1. Modules\ripple_data\protocol + + + 1. Modules\ripple_data\protocol + diff --git a/src/cpp/ripple/AccountSetTransactor.cpp b/src/cpp/ripple/AccountSetTransactor.cpp index 688c6597b1..669606af62 100644 --- a/src/cpp/ripple/AccountSetTransactor.cpp +++ b/src/cpp/ripple/AccountSetTransactor.cpp @@ -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."; diff --git a/src/cpp/ripple/HashPrefixes.h b/src/cpp/ripple/HashPrefixes.h deleted file mode 100644 index 3f5398118e..0000000000 --- a/src/cpp/ripple/HashPrefixes.h +++ /dev/null @@ -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 diff --git a/src/cpp/ripple/Ledger.cpp b/src/cpp/ripple/Ledger.cpp index f7e689065a..7382d7a71f 100644 --- a/src/cpp/ripple/Ledger.cpp +++ b/src/cpp/ripple/Ledger.cpp @@ -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); diff --git a/src/cpp/ripple/NetworkOPs.cpp b/src/cpp/ripple/NetworkOPs.cpp index 0ac1861283..9c58969508 100644 --- a/src/cpp/ripple/NetworkOPs.cpp +++ b/src/cpp/ripple/NetworkOPs.cpp @@ -2172,7 +2172,7 @@ void NetworkOPs::makeFetchPack (Job&, boost::weak_ptr 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); diff --git a/src/cpp/ripple/RPCHandler.cpp b/src/cpp/ripple/RPCHandler.cpp index 9c7a76714a..ee79804f3a 100644 --- a/src/cpp/ripple/RPCHandler.cpp +++ b/src/cpp/ripple/RPCHandler.cpp @@ -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 (lSnapshot); + RippleLineCache::pointer cache = boost::make_shared (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 (lSnapShot); + RippleLineCache::pointer cache = boost::make_shared (lSnapShot); for (unsigned int i = 0; i != jvSrcCurrencies.size (); ++i) { diff --git a/src/cpp/ripple/RPCServer.h b/src/cpp/ripple/RPCServer.h index 3ccc261f75..5d295e56a3 100644 --- a/src/cpp/ripple/RPCServer.h +++ b/src/cpp/ripple/RPCServer.h @@ -3,7 +3,6 @@ #include "HTTPRequest.h" #include "RPCHandler.h" -#include "LoadManager.h" class RPCServer : public boost::enable_shared_from_this { diff --git a/src/cpp/ripple/RippleCalc.h b/src/cpp/ripple/RippleCalc.h deleted file mode 100644 index 13fb3d7b5c..0000000000 --- a/src/cpp/ripple/RippleCalc.h +++ /dev/null @@ -1,236 +0,0 @@ -#ifndef __RIPPLE_CALC__ -#define __RIPPLE_CALC__ - -#include -#include - -#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 aciSource; -typedef boost::unordered_map curIssuerNode; // Map of currency, issuer to node index. -typedef boost::unordered_map::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 pointer; - typedef const boost::shared_ptr& ref; - - TER terStatus; - std::vector vpnNodes; - - // When processing, don't want to complicate directory walking with deletion. - std::vector 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 (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 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& 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& vpsExpanded, bool bKeepDefault); - -protected: - LedgerEntrySet& lesActive; - bool mOpenLedger; -}; - -#endif -// vim:ts=4 diff --git a/src/cpp/ripple/ripple_AccountItem.h b/src/cpp/ripple/ripple_AccountItem.h index 095f43f24c..84011b272d 100644 --- a/src/cpp/ripple/ripple_AccountItem.h +++ b/src/cpp/ripple/ripple_AccountItem.h @@ -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 () diff --git a/src/cpp/ripple/ripple_Application.cpp b/src/cpp/ripple/ripple_Application.cpp index 27614f93b1..8b12937047 100644 --- a/src/cpp/ripple/ripple_Application.cpp +++ b/src/cpp/ripple/ripple_Application.cpp @@ -1,8 +1,7 @@ - +// VFALCO TODO Wrap this up in something neater. Replace NULL with nullptr IApplication* theApp = NULL; - class Application; SETUP_LOG (Application) diff --git a/src/cpp/ripple/ripple_Config.cpp b/src/cpp/ripple/ripple_Config.cpp index 7802266b22..803073b78f 100644 --- a/src/cpp/ripple/ripple_Config.cpp +++ b/src/cpp/ripple/ripple_Config.cpp @@ -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 ()); diff --git a/src/cpp/ripple/ripple_IApplication.h b/src/cpp/ripple/ripple_IApplication.h index ebec3ecc2c..95573818a4 100644 --- a/src/cpp/ripple/ripple_IApplication.h +++ b/src/cpp/ripple/ripple_IApplication.h @@ -108,4 +108,3 @@ public: extern IApplication* theApp; #endif -// vim:ts=4 diff --git a/src/cpp/ripple/ripple_JobQueue.h b/src/cpp/ripple/ripple_JobQueue.h index 1e5a20141a..541cb949b5 100644 --- a/src/cpp/ripple/ripple_JobQueue.h +++ b/src/cpp/ripple/ripple_JobQueue.h @@ -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 (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)); diff --git a/src/cpp/ripple/ripple_LedgerAcquire.cpp b/src/cpp/ripple/ripple_LedgerAcquire.cpp index 125241154e..b57156463b 100644 --- a/src/cpp/ripple/ripple_LedgerAcquire.cpp +++ b/src/cpp/ripple/ripple_LedgerAcquire.cpp @@ -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); diff --git a/src/cpp/ripple/ripple_LoadEvent.h b/src/cpp/ripple/ripple_LoadEvent.h index 6f260b0c27..6ad16e218c 100644 --- a/src/cpp/ripple/ripple_LoadEvent.h +++ b/src/cpp/ripple/ripple_LoadEvent.h @@ -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 pointer; - typedef UPTR_T 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 pointer; + typedef UPTR_T 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); diff --git a/src/cpp/ripple/LoadManager.cpp b/src/cpp/ripple/ripple_LoadManager.cpp similarity index 89% rename from src/cpp/ripple/LoadManager.cpp rename to src/cpp/ripple/ripple_LoadManager.cpp index 87140a6ae3..b8d6ead7cf 100644 --- a/src/cpp/ripple/LoadManager.cpp +++ b/src/cpp/ripple/ripple_LoadManager.cpp @@ -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 (t)]; + Cost cost = mCosts[static_cast (t)]; return adjust (source, cost.mCost); } diff --git a/src/cpp/ripple/LoadManager.h b/src/cpp/ripple/ripple_LoadManager.h similarity index 72% rename from src/cpp/ripple/LoadManager.h rename to src/cpp/ripple/ripple_LoadManager.h index 32342e9967..4a84a10c29 100644 --- a/src/cpp/ripple/LoadManager.h +++ b/src/cpp/ripple/ripple_LoadManager.h @@ -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 (t)].mCost; + return mCosts [static_cast (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 (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 (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 mCosts; + std::vector mCosts; }; #endif diff --git a/src/cpp/ripple/ripple_LoadMonitor.h b/src/cpp/ripple/ripple_LoadMonitor.h index bc98600b88..b15d183343 100644 --- a/src/cpp/ripple/ripple_LoadMonitor.h +++ b/src/cpp/ripple/ripple_LoadMonitor.h @@ -3,6 +3,8 @@ // Monitors load levels and response times +// VFALCO TODO Rename this. Having both LoadManager and LoadMonitor is confusing. +// class LoadMonitor { public: diff --git a/src/cpp/ripple/NicknameState.cpp b/src/cpp/ripple/ripple_NicknameState.cpp similarity index 100% rename from src/cpp/ripple/NicknameState.cpp rename to src/cpp/ripple/ripple_NicknameState.cpp diff --git a/src/cpp/ripple/NicknameState.h b/src/cpp/ripple/ripple_NicknameState.h similarity index 100% rename from src/cpp/ripple/NicknameState.h rename to src/cpp/ripple/ripple_NicknameState.h diff --git a/src/cpp/ripple/Offer.cpp b/src/cpp/ripple/ripple_Offer.cpp similarity index 100% rename from src/cpp/ripple/Offer.cpp rename to src/cpp/ripple/ripple_Offer.cpp diff --git a/src/cpp/ripple/Offer.h b/src/cpp/ripple/ripple_Offer.h similarity index 100% rename from src/cpp/ripple/Offer.h rename to src/cpp/ripple/ripple_Offer.h diff --git a/src/cpp/ripple/ripple_PathRequest.cpp b/src/cpp/ripple/ripple_PathRequest.cpp index 180ec051c8..978d7d6e43 100644 --- a/src/cpp/ripple/ripple_PathRequest.cpp +++ b/src/cpp/ripple/ripple_PathRequest.cpp @@ -95,7 +95,7 @@ Json::Value PathRequest::doCreate (Ledger::ref lrLedger, const Json::Value& valu if (mValid) { - RLCache::pointer cache = boost::make_shared (lrLedger); + RippleLineCache::pointer cache = boost::make_shared (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 (ledger); + RippleLineCache::pointer cache = boost::make_shared (ledger); BOOST_FOREACH (wref wRequest, requests) { diff --git a/src/cpp/ripple/ripple_PathRequest.h b/src/cpp/ripple/ripple_PathRequest.h index 1badbb65a9..7e253ebd21 100644 --- a/src/cpp/ripple/ripple_PathRequest.h +++ b/src/cpp/ripple/ripple_PathRequest.h @@ -1,22 +1,12 @@ -#ifndef _PFREQUEST__H -#define _PFREQUEST__H - -#include -#include - -#include -#include -#include -#include - -#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&, bool fast); // update jvStatus + bool doUpdate (const boost::shared_ptr&, bool fast); // update jvStatus static void updateAll (const boost::shared_ptr& ledger, bool newOnly); diff --git a/src/cpp/ripple/ripple_PathState.cpp b/src/cpp/ripple/ripple_PathState.cpp new file mode 100644 index 0000000000..7533c72c6c --- /dev/null +++ b/src/cpp/ripple/ripple_PathState.cpp @@ -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; +} + diff --git a/src/cpp/ripple/ripple_PathState.h b/src/cpp/ripple/ripple_PathState.h new file mode 100644 index 0000000000..af7e3d2447 --- /dev/null +++ b/src/cpp/ripple/ripple_PathState.h @@ -0,0 +1,158 @@ +#ifndef RIPPLE_PATHSTATE_H +#define RIPPLE_PATHSTATE_H + +// account id, currency id, issuer id :: node +typedef boost::tuple aciSource; +typedef boost::unordered_map curIssuerNode; // Map of currency, issuer to node index. +typedef boost::unordered_map ::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 pointer; + typedef const boost::shared_ptr& 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 (pspExpanded->saOutAct, pspExpanded->saInAct); + + pspNew->setCanonical (pspExpanded); + + return pspNew; + } +#endif + static bool lessPriority (PathState& lhs, PathState& rhs); + +public: + TER terStatus; + std::vector vpnNodes; + + // When processing, don't want to complicate directory walking with deletion. + std::vector 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 diff --git a/src/cpp/ripple/Pathfinder.cpp b/src/cpp/ripple/ripple_Pathfinder.cpp similarity index 98% rename from src/cpp/ripple/Pathfinder.cpp rename to src/cpp/ripple/ripple_Pathfinder.cpp index 749af75686..01a24fce0c 100644 --- a/src/cpp/ripple/Pathfinder.cpp +++ b/src/cpp/ripple/ripple_Pathfinder.cpp @@ -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 usAccountDestCurrencies (const RippleAddress& raAc return usCurrencies; } -AccountItems& RLCache::getRippleLines (const uint160& accountID) -{ - boost::mutex::scoped_lock sl (mLock); - boost::unordered_map::iterator it = mRLMap.find (accountID); - - if (it == mRLMap.end ()) - it = mRLMap.insert (std::make_pair (accountID, boost::make_shared - (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); diff --git a/src/cpp/ripple/Pathfinder.h b/src/cpp/ripple/ripple_Pathfinder.h similarity index 78% rename from src/cpp/ripple/Pathfinder.h rename to src/cpp/ripple/ripple_Pathfinder.h index d3971fde8b..db5eb0515f 100644 --- a/src/cpp/ripple/Pathfinder.h +++ b/src/cpp/ripple/ripple_Pathfinder.h @@ -1,11 +1,7 @@ -#ifndef __PATHFINDER__ -#define __PATHFINDER__ - -#include - -#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 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 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 mRLMap; boost::unordered_map, int> mPOMap; // std::list mBuildingPaths; // std::list 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 usAccountDestCurrencies (const RippleAddress& raAccountID, Ledger::ref lrLedger, @@ -105,5 +79,3 @@ boost::unordered_set usAccountSourceCurrencies (const RippleAddress& ra bool includeXRP); #endif - -// vim:ts=4 diff --git a/src/cpp/ripple/RippleCalc.cpp b/src/cpp/ripple/ripple_RippleCalc.cpp similarity index 77% rename from src/cpp/ripple/RippleCalc.cpp rename to src/cpp/ripple/ripple_RippleCalc.cpp index f6b575523d..f288d9ca15 100644 --- a/src/cpp/ripple/RippleCalc.cpp +++ b/src/cpp/ripple/ripple_RippleCalc.cpp @@ -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& 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; diff --git a/src/cpp/ripple/ripple_RippleCalc.h b/src/cpp/ripple/ripple_RippleCalc.h new file mode 100644 index 0000000000..745f1a7cf3 --- /dev/null +++ b/src/cpp/ripple/ripple_RippleCalc.h @@ -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 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& 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& vpsExpanded, bool bKeepDefault); + +protected: + LedgerEntrySet& lesActive; + bool mOpenLedger; +}; + +#endif +// vim:ts=4 diff --git a/src/cpp/ripple/ripple_RippleLineCache.cpp b/src/cpp/ripple/ripple_RippleLineCache.cpp new file mode 100644 index 0000000000..c71ebfc313 --- /dev/null +++ b/src/cpp/ripple/ripple_RippleLineCache.cpp @@ -0,0 +1,13 @@ + +AccountItems& RippleLineCache::getRippleLines (const uint160& accountID) +{ + boost::mutex::scoped_lock sl (mLock); + + boost::unordered_map ::iterator it = mRLMap.find (accountID); + + if (it == mRLMap.end ()) + it = mRLMap.insert (std::make_pair (accountID, boost::make_shared + (boost::cref (accountID), boost::cref (mLedger), AccountItem::pointer (new RippleState ())))).first; + + return *it->second; +} diff --git a/src/cpp/ripple/ripple_RippleLineCache.h b/src/cpp/ripple/ripple_RippleLineCache.h new file mode 100644 index 0000000000..22ecdde83d --- /dev/null +++ b/src/cpp/ripple/ripple_RippleLineCache.h @@ -0,0 +1,31 @@ +#ifndef RIPPLE_RIPPLELINECACHE_H +#define RIPPLE_RIPPLELINECACHE_H + +// Used by Pathfinder +class RippleLineCache +{ +public: + typedef boost::shared_ptr 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 mRLMap; +}; + +#endif diff --git a/src/cpp/ripple/RippleState.cpp b/src/cpp/ripple/ripple_RippleState.cpp similarity index 100% rename from src/cpp/ripple/RippleState.cpp rename to src/cpp/ripple/ripple_RippleState.cpp diff --git a/src/cpp/ripple/RippleState.h b/src/cpp/ripple/ripple_RippleState.h similarity index 72% rename from src/cpp/ripple/RippleState.h rename to src/cpp/ripple/ripple_RippleState.h index 4bc48dc2e9..518f49c391 100644 --- a/src/cpp/ripple/RippleState.h +++ b/src/cpp/ripple/ripple_RippleState.h @@ -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 pointer; + typedef boost::shared_ptr 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 diff --git a/src/cpp/ripple/ripple_SHAMapSyncFilters.cpp b/src/cpp/ripple/ripple_SHAMapSyncFilters.cpp index 0829a44eac..176483772a 100644 --- a/src/cpp/ripple/ripple_SHAMapSyncFilters.cpp +++ b/src/cpp/ripple/ripple_SHAMapSyncFilters.cpp @@ -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 (); diff --git a/src/cpp/ripple/ripple_SHAMapTreeNode.cpp b/src/cpp/ripple/ripple_SHAMapTreeNode.cpp index 0adaea23f7..4b683e3fee 100644 --- a/src/cpp/ripple/ripple_SHAMapTreeNode.cpp +++ b/src/cpp/ripple/ripple_SHAMapTreeNode.cpp @@ -44,7 +44,7 @@ SHAMapTreeNode::SHAMapTreeNode (const SHAMapNode& id, Blob const& rawNode, uint3 if (type == 0) { // transaction - mItem = boost::make_shared (s.getPrefixHash (sHP_TransactionID), s.peekData ()); + mItem = boost::make_shared (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 (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 (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 (mHashes), sizeof (mHashes)); + nh = Serializer::getPrefixHash (HashPrefix::innerNode, reinterpret_cast (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 ()); } diff --git a/src/cpp/ripple/ripple_SerializedLedger.h b/src/cpp/ripple/ripple_SerializedLedger.h index fc269accc1..1bae70a9d9 100644 --- a/src/cpp/ripple/ripple_SerializedLedger.h +++ b/src/cpp/ripple/ripple_SerializedLedger.h @@ -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: diff --git a/src/cpp/ripple/ripple_SerializedTransaction.cpp b/src/cpp/ripple/ripple_SerializedTransaction.cpp index eed28e59b8..1f739d8a6c 100644 --- a/src/cpp/ripple/ripple_SerializedTransaction.cpp +++ b/src/cpp/ripple/ripple_SerializedTransaction.cpp @@ -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 (getFieldU16 (sfTransactionType)); - mFormat = TransactionFormat::getTxnFormat (mType); + mType = static_cast (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 (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 diff --git a/src/cpp/ripple/ripple_SerializedTransaction.h b/src/cpp/ripple/ripple_SerializedTransaction.h index 22ba554291..a9aa6253b2 100644 --- a/src/cpp/ripple/ripple_SerializedTransaction.h +++ b/src/cpp/ripple/ripple_SerializedTransaction.h @@ -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 {