mirror of
https://github.com/XRPLF/rippled.git
synced 2025-11-30 07:55:51 +00:00
Use Books in Ledger.
This commit is contained in:
committed by
Vinnie Falco
parent
3e9c702c47
commit
6014b13234
@@ -2034,6 +2034,9 @@
|
||||
</ClCompile>
|
||||
<ClInclude Include="..\..\src\ripple\module\app\ledger\AcceptedLedgerTx.h">
|
||||
</ClInclude>
|
||||
<ClCompile Include="..\..\src\ripple\module\app\ledger\BookListeners.cpp">
|
||||
<ExcludedFromBuild>True</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\ripple\module\app\ledger\DirectoryEntryIterator.cpp">
|
||||
<ExcludedFromBuild>True</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
@@ -3200,16 +3203,16 @@
|
||||
<ClInclude Include="..\..\src\ripple\peerfinder\sim\WrappedSink.h">
|
||||
</ClInclude>
|
||||
<CustomBuild Include="..\..\src\ripple\proto\ripple.proto">
|
||||
<FileType>Document</FileType>
|
||||
<Command Condition="'$(Configuration)|$(Platform)'=='debug|x64'">protoc --cpp_out=..\..\build\proto --proto_path=%(RelativeDir) %(Identity)</Command>
|
||||
<Outputs Condition="'$(Configuration)|$(Platform)'=='debug|x64'">..\..\build\proto\ripple.pb.h;..\..\build\proto\ripple.pb.cc</Outputs>
|
||||
<Message Condition="'$(Configuration)|$(Platform)'=='debug|x64'">protoc --cpp_out=..\..\build\proto --proto_path=%(RelativeDir) %(Identity)</Message>
|
||||
<LinkObjects Condition="'$(Configuration)|$(Platform)'=='debug|x64'">false</LinkObjects>
|
||||
<FileType>Document</FileType>
|
||||
<Command Condition="'$(Configuration)|$(Platform)'=='release|x64'">protoc --cpp_out=..\..\build\proto --proto_path=%(RelativeDir) %(Identity)</Command>
|
||||
<Outputs Condition="'$(Configuration)|$(Platform)'=='release|x64'">..\..\build\proto\ripple.pb.h;..\..\build\proto\ripple.pb.cc</Outputs>
|
||||
<Message Condition="'$(Configuration)|$(Platform)'=='release|x64'">protoc --cpp_out=..\..\build\proto --proto_path=%(RelativeDir) %(Identity)</Message>
|
||||
<LinkObjects Condition="'$(Configuration)|$(Platform)'=='release|x64'">false</LinkObjects>
|
||||
<FileType>Document</FileType>
|
||||
<Command Condition="'$(Configuration)|$(Platform)'=='debug|x64'">protoc --cpp_out=..\..\build\proto --proto_path=%(RelativeDir) %(Identity)</Command>
|
||||
<Outputs Condition="'$(Configuration)|$(Platform)'=='debug|x64'">..\..\build\proto\ripple.pb.h;..\..\build\proto\ripple.pb.cc</Outputs>
|
||||
<Message Condition="'$(Configuration)|$(Platform)'=='debug|x64'">protoc --cpp_out=..\..\build\proto --proto_path=%(RelativeDir) %(Identity)</Message>
|
||||
<LinkObjects Condition="'$(Configuration)|$(Platform)'=='debug|x64'">false</LinkObjects>
|
||||
</CustomBuild>
|
||||
<ClInclude Include="..\..\src\ripple\radmap\api\BasicFullBelowCache.h">
|
||||
</ClInclude>
|
||||
@@ -3444,8 +3447,8 @@
|
||||
<ClInclude Include="..\..\src\ripple\unity\http.h">
|
||||
</ClInclude>
|
||||
<ClCompile Include="..\..\src\ripple\unity\hyperleveldb.cpp">
|
||||
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='debug|x64'">..\..\src\hyperleveldb;..\..\src\snappy\config;..\..\src\snappy\snappy;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='release|x64'">..\..\src\hyperleveldb;..\..\src\snappy\config;..\..\src\snappy\snappy;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='debug|x64'">..\..\src\hyperleveldb;..\..\src\snappy\config;..\..\src\snappy\snappy;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<ClInclude Include="..\..\src\ripple\unity\hyperleveldb.h">
|
||||
</ClInclude>
|
||||
@@ -3454,8 +3457,8 @@
|
||||
<ClInclude Include="..\..\src\ripple\unity\json.h">
|
||||
</ClInclude>
|
||||
<ClCompile Include="..\..\src\ripple\unity\leveldb.cpp">
|
||||
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='debug|x64'">..\..\src\leveldb;..\..\src\leveldb\include;..\..\src\snappy\config;..\..\src\snappy\snappy;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='release|x64'">..\..\src\leveldb;..\..\src\leveldb\include;..\..\src\snappy\config;..\..\src\snappy\snappy;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='debug|x64'">..\..\src\leveldb;..\..\src\leveldb\include;..\..\src\snappy\config;..\..\src\snappy\snappy;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<ClInclude Include="..\..\src\ripple\unity\leveldb.h">
|
||||
</ClInclude>
|
||||
@@ -3464,8 +3467,8 @@
|
||||
<ClInclude Include="..\..\src\ripple\unity\net.h">
|
||||
</ClInclude>
|
||||
<ClCompile Include="..\..\src\ripple\unity\nodestore.cpp">
|
||||
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='debug|x64'">..\..\src\leveldb\include;..\..\src\rocksdb\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='release|x64'">..\..\src\leveldb\include;..\..\src\rocksdb\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='debug|x64'">..\..\src\leveldb\include;..\..\src\rocksdb\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\ripple\unity\overlay.cpp">
|
||||
</ClCompile>
|
||||
@@ -3486,8 +3489,8 @@
|
||||
<ClCompile Include="..\..\src\ripple\unity\ripple.proto.cpp">
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\ripple\unity\rocksdb.cpp">
|
||||
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='debug|x64'">..\..\src\rocksdb;..\..\src\rocksdb\include;..\..\src\snappy\config;..\..\src\snappy\snappy;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='release|x64'">..\..\src\rocksdb;..\..\src\rocksdb\include;..\..\src\snappy\config;..\..\src\snappy\snappy;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='debug|x64'">..\..\src\rocksdb;..\..\src\rocksdb\include;..\..\src\snappy\config;..\..\src\snappy\snappy;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<ClInclude Include="..\..\src\ripple\unity\rocksdb.h">
|
||||
</ClInclude>
|
||||
@@ -3500,8 +3503,8 @@
|
||||
<ClInclude Include="..\..\src\ripple\unity\sitefiles.h">
|
||||
</ClInclude>
|
||||
<ClCompile Include="..\..\src\ripple\unity\snappy.cpp">
|
||||
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='debug|x64'">..\..\src\snappy\config;..\..\src\snappy\snappy;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='release|x64'">..\..\src\snappy\config;..\..\src\snappy\snappy;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='debug|x64'">..\..\src\snappy\config;..\..\src\snappy\snappy;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\ripple\unity\sslutil.cpp">
|
||||
</ClCompile>
|
||||
|
||||
@@ -3027,6 +3027,9 @@
|
||||
<ClInclude Include="..\..\src\ripple\module\app\ledger\AcceptedLedgerTx.h">
|
||||
<Filter>ripple\module\app\ledger</Filter>
|
||||
</ClInclude>
|
||||
<ClCompile Include="..\..\src\ripple\module\app\ledger\BookListeners.cpp">
|
||||
<Filter>ripple\module\app\ledger</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\ripple\module\app\ledger\DirectoryEntryIterator.cpp">
|
||||
<Filter>ripple\module\app\ledger</Filter>
|
||||
</ClCompile>
|
||||
|
||||
@@ -25,9 +25,7 @@ namespace core {
|
||||
BookTip::BookTip (LedgerView& view, BookRef book)
|
||||
: m_view (view)
|
||||
, m_valid (false)
|
||||
, m_book (Ledger::getBookBase (
|
||||
book.in.currency, book.in.account,
|
||||
book.out.currency, book.out.account))
|
||||
, m_book (Ledger::getBookBase (book))
|
||||
, m_end (Ledger::getQualityNext (m_book))
|
||||
{
|
||||
}
|
||||
|
||||
56
src/ripple/module/app/ledger/BookListeners.cpp
Normal file
56
src/ripple/module/app/ledger/BookListeners.cpp
Normal file
@@ -0,0 +1,56 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
namespace ripple {
|
||||
|
||||
void BookListeners::addSubscriber (InfoSub::ref sub)
|
||||
{
|
||||
ScopedLockType sl (mLock);
|
||||
mListeners[sub->getSeq ()] = sub;
|
||||
}
|
||||
|
||||
void BookListeners::removeSubscriber (std::uint64_t seq)
|
||||
{
|
||||
ScopedLockType sl (mLock);
|
||||
mListeners.erase (seq);
|
||||
}
|
||||
|
||||
void BookListeners::publish (Json::Value const& jvObj)
|
||||
{
|
||||
Json::FastWriter jfwWriter;
|
||||
std::string sObj = jfwWriter.write (jvObj);
|
||||
|
||||
ScopedLockType sl (mLock);
|
||||
NetworkOPs::SubMapType::const_iterator it = mListeners.begin ();
|
||||
|
||||
while (it != mListeners.end ())
|
||||
{
|
||||
InfoSub::pointer p = it->second.lock ();
|
||||
|
||||
if (p)
|
||||
{
|
||||
p->send (jvObj, sObj, true);
|
||||
++it;
|
||||
}
|
||||
else
|
||||
it = mListeners.erase (it);
|
||||
}
|
||||
}
|
||||
|
||||
} // ripple
|
||||
@@ -17,19 +17,31 @@
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef RIPPLE_BOOKLISTENERS_H
|
||||
#define RIPPLE_BOOKLISTENERS_H
|
||||
|
||||
namespace ripple {
|
||||
|
||||
OrderBook::OrderBook (uint256 const& index,
|
||||
Currency const& currencyIn,
|
||||
Currency const& currencyOut,
|
||||
Account const& issuerIn,
|
||||
Account const& issuerOut)
|
||||
: mBookBase (index)
|
||||
, mCurrencyIn (currencyIn)
|
||||
, mCurrencyOut (currencyOut)
|
||||
, mIssuerIn (issuerIn)
|
||||
, mIssuerOut (issuerOut)
|
||||
/** Listen to public/subscribe messages from a book. */
|
||||
class BookListeners
|
||||
{
|
||||
}
|
||||
public:
|
||||
typedef std::shared_ptr<BookListeners> pointer;
|
||||
|
||||
BookListeners () {}
|
||||
|
||||
void addSubscriber (InfoSub::ref sub);
|
||||
void removeSubscriber (std::uint64_t sub);
|
||||
void publish (Json::Value const& jvObj);
|
||||
|
||||
private:
|
||||
typedef RippleRecursiveMutex LockType;
|
||||
typedef std::lock_guard <LockType> ScopedLockType;
|
||||
LockType mLock;
|
||||
|
||||
ripple::unordered_map<std::uint64_t, InfoSub::wptr> mListeners;
|
||||
};
|
||||
|
||||
} // ripple
|
||||
|
||||
#endif
|
||||
@@ -242,16 +242,18 @@ Ledger::~Ledger ()
|
||||
{
|
||||
if (mTransactionMap)
|
||||
{
|
||||
logTimedDestroy <Ledger> (mTransactionMap,
|
||||
beast::String ("mTransactionMap with ") +
|
||||
beast::String::fromNumber (mTransactionMap->size ()) + " items");
|
||||
logTimedDestroy <Ledger> (
|
||||
mTransactionMap,
|
||||
"mTransactionMap with "
|
||||
+ std::to_string(mTransactionMap->size ()) + " items");
|
||||
}
|
||||
|
||||
if (mAccountStateMap)
|
||||
{
|
||||
logTimedDestroy <Ledger> (mAccountStateMap,
|
||||
beast::String ("mAccountStateMap with ") +
|
||||
beast::String::fromNumber (mAccountStateMap->size ()) + " items");
|
||||
logTimedDestroy <Ledger> (
|
||||
mAccountStateMap,
|
||||
"mAccountStateMap with "
|
||||
+ std::to_string (mAccountStateMap->size ()) + " items");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -614,17 +616,27 @@ uint256 Ledger::getHash ()
|
||||
bool Ledger::saveValidatedLedger (bool current)
|
||||
{
|
||||
// TODO(tom): Fix this hard-coded SQL!
|
||||
WriteLog (lsTRACE, Ledger) << "saveValidatedLedger " << (current ? "" : "fromAcquire ") << getLedgerSeq ();
|
||||
static boost::format deleteLedger ("DELETE FROM Ledgers WHERE LedgerSeq = %u;");
|
||||
static boost::format deleteTrans1 ("DELETE FROM Transactions WHERE LedgerSeq = %u;");
|
||||
static boost::format deleteTrans2 ("DELETE FROM AccountTransactions WHERE LedgerSeq = %u;");
|
||||
static boost::format deleteAcctTrans ("DELETE FROM AccountTransactions WHERE TransID = '%s';");
|
||||
static boost::format transExists ("SELECT Status FROM Transactions WHERE TransID = '%s';");
|
||||
static boost::format
|
||||
updateTx ("UPDATE Transactions SET LedgerSeq = %u, Status = '%c', TxnMeta = %s WHERE TransID = '%s';");
|
||||
static boost::format addLedger ("INSERT OR REPLACE INTO Ledgers "
|
||||
"(LedgerHash,LedgerSeq,PrevHash,TotalCoins,ClosingTime,PrevClosingTime,CloseTimeRes,CloseFlags,"
|
||||
"AccountSetHash,TransSetHash) VALUES ('%s','%u','%s','%s','%u','%u','%d','%u','%s','%s');");
|
||||
WriteLog (lsTRACE, Ledger)
|
||||
<< "saveValidatedLedger "
|
||||
<< (current ? "" : "fromAcquire ") << getLedgerSeq ();
|
||||
static boost::format deleteLedger (
|
||||
"DELETE FROM Ledgers WHERE LedgerSeq = %u;");
|
||||
static boost::format deleteTrans1 (
|
||||
"DELETE FROM Transactions WHERE LedgerSeq = %u;");
|
||||
static boost::format deleteTrans2 (
|
||||
"DELETE FROM AccountTransactions WHERE LedgerSeq = %u;");
|
||||
static boost::format deleteAcctTrans (
|
||||
"DELETE FROM AccountTransactions WHERE TransID = '%s';");
|
||||
static boost::format transExists (
|
||||
"SELECT Status FROM Transactions WHERE TransID = '%s';");
|
||||
static boost::format updateTx (
|
||||
"UPDATE Transactions SET LedgerSeq = %u, Status = '%c', TxnMeta = %s "
|
||||
"WHERE TransID = '%s';");
|
||||
static boost::format addLedger (
|
||||
"INSERT OR REPLACE INTO Ledgers "
|
||||
"(LedgerHash,LedgerSeq,PrevHash,TotalCoins,ClosingTime,PrevClosingTime,"
|
||||
"CloseTimeRes,CloseFlags,AccountSetHash,TransSetHash) VALUES "
|
||||
"('%s','%u','%s','%s','%u','%u','%d','%u','%s','%s');");
|
||||
|
||||
if (!getAccountHash ().isNonZero ())
|
||||
{
|
||||
@@ -738,10 +750,14 @@ bool Ledger::saveValidatedLedger (bool current)
|
||||
db->executeSQL (sql);
|
||||
}
|
||||
else
|
||||
WriteLog (lsWARNING, Ledger) << "Transaction in ledger " << mLedgerSeq << " affects no accounts";
|
||||
WriteLog (lsWARNING, Ledger)
|
||||
<< "Transaction in ledger " << mLedgerSeq
|
||||
<< " affects no accounts";
|
||||
|
||||
db->executeSQL (SerializedTransaction::getMetaSQLInsertReplaceHeader () +
|
||||
vt.second->getTxn ()->getMetaSQL (getLedgerSeq (), vt.second->getEscMeta ()) + ";");
|
||||
db->executeSQL (
|
||||
SerializedTransaction::getMetaSQLInsertReplaceHeader () +
|
||||
vt.second->getTxn ()->getMetaSQL (
|
||||
getLedgerSeq (), vt.second->getEscMeta ()) + ";");
|
||||
}
|
||||
db->executeSQL ("COMMIT TRANSACTION;");
|
||||
}
|
||||
@@ -749,7 +765,7 @@ bool Ledger::saveValidatedLedger (bool current)
|
||||
{
|
||||
DeprecatedScopedLock sl (getApp().getLedgerDB ()->getDBLock ());
|
||||
|
||||
// TODO(tom): ARG!
|
||||
// TODO(tom): ARG!!
|
||||
getApp().getLedgerDB ()->getDB ()->executeSQL (boost::str (addLedger %
|
||||
to_string (getHash ()) % mLedgerSeq % to_string (mParentHash) %
|
||||
beast::lexicalCastThrow <std::string> (mTotCoins) % mCloseTime %
|
||||
@@ -1266,7 +1282,8 @@ LedgerStateParms Ledger::writeBack (LedgerStateParms parms, SLE::ref entry)
|
||||
{
|
||||
if ((parms & lepCREATE) == 0)
|
||||
{
|
||||
WriteLog (lsERROR, Ledger) << "WriteBack non-existent node without create";
|
||||
WriteLog (lsERROR, Ledger)
|
||||
<< "WriteBack non-existent node without create";
|
||||
return lepMISSING;
|
||||
}
|
||||
|
||||
@@ -1343,9 +1360,9 @@ void Ledger::visitAccountItems (
|
||||
if (!ownerDir || (ownerDir->getType () != ltDIR_NODE))
|
||||
return;
|
||||
|
||||
for (auto const& uNode : ownerDir->getFieldV256 (sfIndexes).peekValue ())
|
||||
for (auto const& node : ownerDir->getFieldV256 (sfIndexes).peekValue ())
|
||||
{
|
||||
func (getSLEi (uNode));
|
||||
func (getSLEi (node));
|
||||
}
|
||||
|
||||
std::uint64_t uNodeNext = ownerDir->getFieldU64 (sfIndexNext);
|
||||
@@ -1386,49 +1403,6 @@ void Ledger::visitStateItems (std::function<void (SLE::ref)> function)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
// VFALCO: A proof of concept for making an iterator instead of a visitor
|
||||
class AccountItemIterator
|
||||
{
|
||||
public:
|
||||
explicit AccountItemIterator (Account const& accountID)
|
||||
{
|
||||
// Convert the account ID to the root hash
|
||||
//
|
||||
m_rootKey = Ledger::getOwnerDirIndex (accountID);
|
||||
|
||||
// Start iterating from the root
|
||||
//
|
||||
m_currentKey = rootKey;
|
||||
|
||||
}
|
||||
|
||||
SerializedLedgerEntry::ref operator* () const
|
||||
{
|
||||
return m_currentEntry;
|
||||
}
|
||||
|
||||
SerializedLedgerEntry::ref end () const
|
||||
{
|
||||
return s_end;
|
||||
}
|
||||
|
||||
AccountItemIterator& operator++ (int)
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
static SerializedLedgerEntry s_end;
|
||||
|
||||
uint256 m_rootKey;
|
||||
uint256 m_currentKey;
|
||||
|
||||
SerializedLedgerEntry::pointer m_currentEntry;
|
||||
}
|
||||
// typedef const std::shared_ptr<SerializedLedgerEntry>& ref;
|
||||
*/
|
||||
|
||||
|
||||
uint256 Ledger::getFirstLedgerIndex ()
|
||||
{
|
||||
SHAMapItem::pointer node = mAccountStateMap->peekFirstItem ();
|
||||
@@ -1703,9 +1677,9 @@ uint256 Ledger::getLedgerHash (std::uint32_t ledgerIndex)
|
||||
return uint256 ();
|
||||
}
|
||||
|
||||
std::vector< std::pair<std::uint32_t, uint256> > Ledger::getLedgerHashes ()
|
||||
Ledger::LedgerHashes Ledger::getLedgerHashes ()
|
||||
{
|
||||
std::vector< std::pair<std::uint32_t, uint256> > ret;
|
||||
LedgerHashes ret;
|
||||
SLE::pointer hashIndex = getSLEi (getLedgerHashIndex ());
|
||||
|
||||
if (hashIndex)
|
||||
@@ -1733,74 +1707,23 @@ std::vector<uint256> Ledger::getLedgerAmendments ()
|
||||
return usAmendments;
|
||||
}
|
||||
|
||||
// XRP to XRP not allowed.
|
||||
// Currencies must have appropriate issuer.
|
||||
// Currencies or accounts must differ.
|
||||
bool Ledger::isValidBook (
|
||||
Currency const& uTakerPaysCurrency, Account const& uTakerPaysIssuerID,
|
||||
Currency const& uTakerGetsCurrency, Account const& uTakerGetsIssuerID)
|
||||
{
|
||||
// TODO(tom): refactor to use == zero, better boolean logic.
|
||||
if (uTakerPaysCurrency.isZero ())
|
||||
{
|
||||
// XRP in
|
||||
|
||||
if (uTakerPaysIssuerID.isNonZero ()) // XRP cannot have an issuer
|
||||
return false;
|
||||
|
||||
if (uTakerGetsCurrency.isZero ()) // XRP to XRP not allowed
|
||||
return false;
|
||||
|
||||
if (uTakerGetsIssuerID.isZero ()) // non-XRP must have issuer
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// non-XRP in
|
||||
if (uTakerPaysIssuerID.isZero ()) // non-XRP must have issuer
|
||||
return false;
|
||||
|
||||
if (uTakerGetsCurrency.isZero ()) // non-XRP to XRP
|
||||
{
|
||||
if (uTakerGetsIssuerID.isNonZero ()) // XRP cannot have issuer
|
||||
return false;
|
||||
}
|
||||
else // non-XRP to non-XRP
|
||||
{
|
||||
// Input and output cannot be identical
|
||||
if ((uTakerPaysCurrency == uTakerGetsCurrency) &&
|
||||
(uTakerGetsIssuerID == uTakerPaysIssuerID))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
uint256 Ledger::getBookBase (
|
||||
Currency const& uTakerPaysCurrency, Account const& uTakerPaysIssuerID,
|
||||
Currency const& uTakerGetsCurrency, Account const& uTakerGetsIssuerID)
|
||||
uint256 Ledger::getBookBase (Book const& book)
|
||||
{
|
||||
Serializer s (82);
|
||||
|
||||
s.add16 (spaceBookDir); // 2
|
||||
s.add160 (uTakerPaysCurrency); // 20
|
||||
s.add160 (uTakerGetsCurrency); // 20
|
||||
s.add160 (uTakerPaysIssuerID); // 20
|
||||
s.add160 (uTakerGetsIssuerID); // 20
|
||||
s.add160 (book.in.currency); // 20
|
||||
s.add160 (book.out.currency); // 20
|
||||
s.add160 (book.in.account); // 20
|
||||
s.add160 (book.out.account); // 20
|
||||
|
||||
uint256 uBaseIndex = getQualityIndex (s.getSHA512Half ()); // Return with quality 0.
|
||||
// Return with quality 0.
|
||||
uint256 uBaseIndex = getQualityIndex (s.getSHA512Half ());
|
||||
|
||||
WriteLog (lsTRACE, Ledger)
|
||||
<< "getBookBase"
|
||||
<< "(" << uTakerPaysCurrency
|
||||
<< "," << uTakerPaysIssuerID
|
||||
<< "," << uTakerGetsCurrency
|
||||
<< "," << uTakerGetsIssuerID
|
||||
<< ") = " << to_string (uBaseIndex);
|
||||
<< "getBookBase (" << book << ") = " << to_string (uBaseIndex);
|
||||
|
||||
assert (isValidBook (uTakerPaysCurrency, uTakerPaysIssuerID,
|
||||
uTakerGetsCurrency, uTakerGetsIssuerID));
|
||||
assert (isConsistent (book));
|
||||
|
||||
return uBaseIndex;
|
||||
}
|
||||
@@ -1894,16 +1817,20 @@ bool Ledger::walkLedger ()
|
||||
|
||||
if (ShouldLog (lsINFO, Ledger) && !missingNodes1.empty ())
|
||||
{
|
||||
WriteLog (lsINFO, Ledger) << missingNodes1.size () << " missing account node(s)";
|
||||
WriteLog (lsINFO, Ledger) << "First: " << missingNodes1[0];
|
||||
WriteLog (lsINFO, Ledger)
|
||||
<< missingNodes1.size () << " missing account node(s)";
|
||||
WriteLog (lsINFO, Ledger)
|
||||
<< "First: " << missingNodes1[0];
|
||||
}
|
||||
|
||||
mTransactionMap->walkMap (missingNodes2, 32);
|
||||
|
||||
if (ShouldLog (lsINFO, Ledger) && !missingNodes2.empty ())
|
||||
{
|
||||
WriteLog (lsINFO, Ledger) << missingNodes2.size () << " missing transaction node(s)";
|
||||
WriteLog (lsINFO, Ledger) << "First: " << missingNodes2[0];
|
||||
WriteLog (lsINFO, Ledger)
|
||||
<< missingNodes2.size () << " missing transaction node(s)";
|
||||
WriteLog (lsINFO, Ledger)
|
||||
<< "First: " << missingNodes2[0];
|
||||
}
|
||||
|
||||
return missingNodes1.empty () && missingNodes2.empty ();
|
||||
@@ -1996,7 +1923,8 @@ void Ledger::updateSkipList ()
|
||||
}
|
||||
}
|
||||
|
||||
std::uint32_t Ledger::roundCloseTime (std::uint32_t closeTime, std::uint32_t closeResolution)
|
||||
std::uint32_t Ledger::roundCloseTime (
|
||||
std::uint32_t closeTime, std::uint32_t closeResolution)
|
||||
{
|
||||
if (closeTime == 0)
|
||||
return 0;
|
||||
@@ -2022,7 +1950,8 @@ bool Ledger::pendSaveValidated (bool isSynchronous, bool isCurrent)
|
||||
StaticScopedLockType sl (sPendingSaveLock);
|
||||
if (!sPendingSaves.insert(getLedgerSeq()).second)
|
||||
{
|
||||
WriteLog (lsDEBUG, Ledger) << "Pend save with seq in pending saves " << getLedgerSeq();
|
||||
WriteLog (lsDEBUG, Ledger)
|
||||
<< "Pend save with seq in pending saves " << getLedgerSeq();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -2072,8 +2001,8 @@ void Ledger::qualityDirDescriber (
|
||||
if (isNew)
|
||||
{
|
||||
getApp().getOrderBookDB().addOrderBook(
|
||||
uTakerPaysCurrency, uTakerGetsCurrency,
|
||||
uTakerPaysIssuer, uTakerGetsIssuer);
|
||||
{{uTakerPaysCurrency, uTakerPaysIssuer},
|
||||
{uTakerGetsCurrency, uTakerGetsIssuer}});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -342,7 +342,8 @@ public:
|
||||
std::uint32_t desiredLedgerIndex, std::uint32_t currentLedgerIndex);
|
||||
|
||||
uint256 getLedgerHash (std::uint32_t ledgerIndex);
|
||||
std::vector< std::pair<std::uint32_t, uint256> > getLedgerHashes ();
|
||||
typedef std::vector<std::pair<std::uint32_t, uint256>> LedgerHashes;
|
||||
LedgerHashes getLedgerHashes ();
|
||||
|
||||
static uint256 getLedgerAmendmentIndex ();
|
||||
static uint256 getLedgerFeeIndex ();
|
||||
@@ -398,13 +399,7 @@ public:
|
||||
|
||||
// Order book dirs have a base so we can use next to step through them in
|
||||
// quality order.
|
||||
static bool isValidBook (
|
||||
Currency const& uTakerPaysCurrency, Account const& uTakerPaysIssuerID,
|
||||
Currency const& uTakerGetsCurrency, Account const& uTakerGetsIssuerID);
|
||||
|
||||
static uint256 getBookBase (
|
||||
Currency const& uTakerPaysCurrency, Account const& uTakerPaysIssuerID,
|
||||
Currency const& uTakerGetsCurrency, Account const& uTakerGetsIssuerID);
|
||||
static uint256 getBookBase (Book const&);
|
||||
|
||||
//
|
||||
// Offer functions
|
||||
|
||||
@@ -33,23 +33,25 @@ void OrderBookDB::invalidate ()
|
||||
|
||||
void OrderBookDB::setup (Ledger::ref ledger)
|
||||
{
|
||||
auto seq = ledger->getLedgerSeq ();
|
||||
{
|
||||
ScopedLockType sl (mLock);
|
||||
|
||||
// Do a full update every 256 ledgers
|
||||
if (mSeq != 0)
|
||||
{
|
||||
if (ledger->getLedgerSeq () == mSeq)
|
||||
if (seq == mSeq)
|
||||
return;
|
||||
if ((ledger->getLedgerSeq () > mSeq) && ((ledger->getLedgerSeq () - mSeq) < 256))
|
||||
if ((seq > mSeq) && ((seq - mSeq) < 256))
|
||||
return;
|
||||
if ((ledger->getLedgerSeq () < mSeq) && ((mSeq - ledger->getLedgerSeq ()) < 16))
|
||||
if ((seq < mSeq) && ((mSeq - seq) < 16))
|
||||
return;
|
||||
}
|
||||
|
||||
WriteLog (lsDEBUG, OrderBookDB) << "Advancing from " << mSeq << " to " << ledger->getLedgerSeq();
|
||||
WriteLog (lsDEBUG, OrderBookDB)
|
||||
<< "Advancing from " << mSeq << " to " << seq;
|
||||
|
||||
mSeq = ledger->getLedgerSeq ();
|
||||
mSeq = seq;
|
||||
}
|
||||
|
||||
if (getConfig().RUN_STANDALONE)
|
||||
@@ -61,34 +63,29 @@ void OrderBookDB::setup (Ledger::ref ledger)
|
||||
|
||||
static void updateHelper (SLE::ref entry,
|
||||
ripple::unordered_set< uint256 >& seen,
|
||||
ripple::unordered_map< Issue, std::vector<OrderBook::pointer> >& destMap,
|
||||
ripple::unordered_map< Issue, std::vector<OrderBook::pointer> >& sourceMap,
|
||||
OrderBookDB::IssueToOrderBook& destMap,
|
||||
OrderBookDB::IssueToOrderBook& sourceMap,
|
||||
ripple::unordered_set< Issue >& XRPBooks,
|
||||
int& books)
|
||||
{
|
||||
if ((entry->getType () == ltDIR_NODE) && (entry->isFieldPresent (sfExchangeRate)) &&
|
||||
(entry->getFieldH256 (sfRootIndex) == entry->getIndex()))
|
||||
if (entry->getType () == ltDIR_NODE &&
|
||||
entry->isFieldPresent (sfExchangeRate) &&
|
||||
entry->getFieldH256 (sfRootIndex) == entry->getIndex())
|
||||
{
|
||||
Currency ci, co;
|
||||
ci.copyFrom (entry->getFieldH160 (sfTakerPaysCurrency));
|
||||
co.copyFrom (entry->getFieldH160 (sfTakerGetsCurrency));
|
||||
|
||||
Account ii, io;
|
||||
ii.copyFrom (entry->getFieldH160 (sfTakerPaysIssuer));
|
||||
io.copyFrom (entry->getFieldH160 (sfTakerGetsIssuer));
|
||||
|
||||
uint256 index = Ledger::getBookBase (ci, ii, co, io);
|
||||
Book book;
|
||||
book.in.currency.copyFrom (entry->getFieldH160 (sfTakerPaysCurrency));
|
||||
book.in.account.copyFrom (entry->getFieldH160 (sfTakerPaysIssuer));
|
||||
book.out.account.copyFrom (entry->getFieldH160 (sfTakerGetsIssuer));
|
||||
book.out.currency.copyFrom (entry->getFieldH160 (sfTakerGetsCurrency));
|
||||
|
||||
uint256 index = Ledger::getBookBase (book);
|
||||
if (seen.insert (index).second)
|
||||
{
|
||||
// VFALCO TODO Reduce the clunkiness of these parameter wrappers
|
||||
OrderBook::pointer book = std::make_shared<OrderBook> (std::cref (index),
|
||||
std::cref (ci), std::cref (co), std::cref (ii), std::cref (io));
|
||||
|
||||
sourceMap[IssueRef (ci, ii)].push_back (book);
|
||||
destMap[IssueRef (co, io)].push_back (book);
|
||||
if (co.isZero())
|
||||
XRPBooks.insert(IssueRef (ci, ii));
|
||||
auto orderBook = std::make_shared<OrderBook> (index, book);
|
||||
sourceMap[book.in].push_back (orderBook);
|
||||
destMap[book.out].push_back (orderBook);
|
||||
if (isXRP(book.out))
|
||||
XRPBooks.insert(book.in);
|
||||
++books;
|
||||
}
|
||||
}
|
||||
@@ -97,8 +94,8 @@ static void updateHelper (SLE::ref entry,
|
||||
void OrderBookDB::update (Ledger::pointer ledger)
|
||||
{
|
||||
ripple::unordered_set< uint256 > seen;
|
||||
ripple::unordered_map< Issue, std::vector<OrderBook::pointer> > destMap;
|
||||
ripple::unordered_map< Issue, std::vector<OrderBook::pointer> > sourceMap;
|
||||
OrderBookDB::IssueToOrderBook destMap;
|
||||
OrderBookDB::IssueToOrderBook sourceMap;
|
||||
ripple::unordered_set< Issue > XRPBooks;
|
||||
|
||||
WriteLog (lsDEBUG, OrderBookDB) << "OrderBookDB::update>";
|
||||
@@ -114,13 +111,15 @@ void OrderBookDB::update (Ledger::pointer ledger)
|
||||
}
|
||||
catch (const SHAMapMissingNode&)
|
||||
{
|
||||
WriteLog (lsINFO, OrderBookDB) << "OrderBookDB::update encountered a missing node";
|
||||
WriteLog (lsINFO, OrderBookDB)
|
||||
<< "OrderBookDB::update encountered a missing node";
|
||||
ScopedLockType sl (mLock);
|
||||
mSeq = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
WriteLog (lsDEBUG, OrderBookDB) << "OrderBookDB::update< " << books << " books found";
|
||||
WriteLog (lsDEBUG, OrderBookDB)
|
||||
<< "OrderBookDB::update< " << books << " books found";
|
||||
{
|
||||
ScopedLockType sl (mLock);
|
||||
|
||||
@@ -131,63 +130,66 @@ void OrderBookDB::update (Ledger::pointer ledger)
|
||||
getApp().getLedgerMaster().newOrderBookDB();
|
||||
}
|
||||
|
||||
void OrderBookDB::addOrderBook(Currency const& ci, Currency const& co,
|
||||
Account const& ii, Account const& io)
|
||||
void OrderBookDB::addOrderBook(Book const& book)
|
||||
{
|
||||
bool toXRP = co.isZero();
|
||||
bool toXRP = isXRP (book.out);
|
||||
ScopedLockType sl (mLock);
|
||||
|
||||
if (toXRP)
|
||||
{ // We don't want to search through all the to-XRP or from-XRP order books!
|
||||
for (auto ob : mSourceMap[{ci, ii}])
|
||||
{
|
||||
if (ob->getCurrencyOut().isZero ()) // also to XRP
|
||||
// We don't want to search through all the to-XRP or from-XRP order
|
||||
// books!
|
||||
for (auto ob: mSourceMap[book.in])
|
||||
{
|
||||
if (isXRP (ob->getCurrencyOut ())) // also to XRP
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (auto ob : mDestMap[{co, io}])
|
||||
for (auto ob: mDestMap[book.out])
|
||||
{
|
||||
if (ob->getCurrencyIn() == book.in.currency &&
|
||||
ob->getIssuerIn() == book.in.account)
|
||||
{
|
||||
if ((ob->getCurrencyIn() == ci) && (ob->getIssuerIn() == ii))
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
uint256 index = Ledger::getBookBase(book);
|
||||
auto orderBook = std::make_shared<OrderBook> (index, book);
|
||||
|
||||
uint256 index = Ledger::getBookBase(ci, ii, co, io);
|
||||
auto book = std::make_shared<OrderBook> (index, ci, co, ii, io);
|
||||
|
||||
mSourceMap[{ci, ii}].push_back (book);
|
||||
mDestMap[{co, io}].push_back (book);
|
||||
mSourceMap[book.in].push_back (orderBook);
|
||||
mDestMap[book.out].push_back (orderBook);
|
||||
if (toXRP)
|
||||
mXRPBooks.insert({ci, ii});
|
||||
mXRPBooks.insert(book.in);
|
||||
}
|
||||
|
||||
// return list of all orderbooks that want this issuerID and currencyID
|
||||
void OrderBookDB::getBooksByTakerPays (Account const& issuerID, Currency const& currencyID,
|
||||
std::vector<OrderBook::pointer>& bookRet)
|
||||
void OrderBookDB::getBooksByTakerPays (
|
||||
Issue const& issue, OrderBook::List& bookRet)
|
||||
{
|
||||
ScopedLockType sl (mLock);
|
||||
auto it = mSourceMap.find ({currencyID, issuerID});
|
||||
auto it = mSourceMap.find (issue);
|
||||
if (it != mSourceMap.end ())
|
||||
bookRet = it->second;
|
||||
else
|
||||
bookRet.clear ();
|
||||
}
|
||||
|
||||
bool OrderBookDB::isBookToXRP(Account const& issuerID, Currency const& currencyID)
|
||||
bool OrderBookDB::isBookToXRP(Issue const& issue)
|
||||
{
|
||||
ScopedLockType sl (mLock);
|
||||
|
||||
return mXRPBooks.count({currencyID, issuerID}) > 0;
|
||||
return mXRPBooks.count(issue) > 0;
|
||||
}
|
||||
|
||||
// return list of all orderbooks that give this issuerID and currencyID
|
||||
void OrderBookDB::getBooksByTakerGets (Account const& issuerID, Currency const& currencyID,
|
||||
std::vector<OrderBook::pointer>& bookRet)
|
||||
void OrderBookDB::getBooksByTakerGets (
|
||||
Issue const& issue, OrderBook::List& bookRet)
|
||||
{
|
||||
ScopedLockType sl (mLock);
|
||||
auto it = mDestMap.find ({currencyID, issuerID});
|
||||
auto it = mDestMap.find (issue);
|
||||
|
||||
if (it != mDestMap.end ())
|
||||
bookRet = it->second;
|
||||
@@ -195,49 +197,46 @@ void OrderBookDB::getBooksByTakerGets (Account const& issuerID, Currency const&
|
||||
bookRet.clear ();
|
||||
}
|
||||
|
||||
BookListeners::pointer OrderBookDB::makeBookListeners (Currency const& currencyPays, Currency const& currencyGets,
|
||||
Account const& issuerPays, Account const& issuerGets)
|
||||
BookListeners::pointer OrderBookDB::makeBookListeners (Book const& book)
|
||||
{
|
||||
ScopedLockType sl (mLock);
|
||||
BookListeners::pointer ret = getBookListeners (currencyPays, currencyGets, issuerPays, issuerGets);
|
||||
auto ret = getBookListeners (book);
|
||||
|
||||
if (!ret)
|
||||
{
|
||||
ret = std::make_shared<BookListeners> ();
|
||||
|
||||
mListeners [BookRef ({currencyPays, issuerPays},
|
||||
{currencyGets, issuerGets})] = ret;
|
||||
assert (getBookListeners (currencyPays, currencyGets, issuerPays, issuerGets) == ret);
|
||||
mListeners [book] = ret;
|
||||
assert (getBookListeners (book) == ret);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
BookListeners::pointer OrderBookDB::getBookListeners (Currency const& currencyPays, Currency const& currencyGets,
|
||||
Account const& issuerPays, Account const& issuerGets)
|
||||
BookListeners::pointer OrderBookDB::getBookListeners (Book const& book)
|
||||
{
|
||||
BookListeners::pointer ret;
|
||||
ScopedLockType sl (mLock);
|
||||
|
||||
auto it0 (mListeners.find (BookRef (
|
||||
{currencyPays, issuerPays}, {currencyGets, issuerGets})));
|
||||
|
||||
auto it0 = mListeners.find (book);
|
||||
if (it0 != mListeners.end ())
|
||||
ret = it0->second;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Based on the meta, send the meta to the streams that are listening
|
||||
// We need to determine which streams a given meta effects
|
||||
void OrderBookDB::processTxn (Ledger::ref ledger, const AcceptedLedgerTx& alTx, Json::Value const& jvObj)
|
||||
// Based on the meta, send the meta to the streams that are listening.
|
||||
// We need to determine which streams a given meta effects.
|
||||
void OrderBookDB::processTxn (
|
||||
Ledger::ref ledger, const AcceptedLedgerTx& alTx, Json::Value const& jvObj)
|
||||
{
|
||||
ScopedLockType sl (mLock);
|
||||
|
||||
if (alTx.getResult () == tesSUCCESS)
|
||||
{
|
||||
// check if this is an offer or an offer cancel or a payment that consumes an offer
|
||||
//check to see what the meta looks like
|
||||
// Check if this is an offer or an offer cancel or a payment that
|
||||
// consumes an offer.
|
||||
// Check to see what the meta looks like.
|
||||
for (auto& node : alTx.getMeta ()->getNodes ())
|
||||
{
|
||||
try
|
||||
@@ -246,90 +245,40 @@ void OrderBookDB::processTxn (Ledger::ref ledger, const AcceptedLedgerTx& alTx,
|
||||
{
|
||||
SField* field = nullptr;
|
||||
|
||||
// We need a field that contains the TakerGets and TakerPays parameters
|
||||
// We need a field that contains the TakerGets and TakerPays
|
||||
// parameters.
|
||||
if (node.getFName () == sfModifiedNode)
|
||||
{
|
||||
field = &sfPreviousFields;
|
||||
}
|
||||
else if (node.getFName () == sfCreatedNode)
|
||||
{
|
||||
field = &sfNewFields;
|
||||
}
|
||||
else if (node.getFName () == sfDeletedNode)
|
||||
{
|
||||
field = &sfFinalFields;
|
||||
}
|
||||
|
||||
if (field)
|
||||
{
|
||||
const STObject* data = dynamic_cast<const STObject*> (node.peekAtPField (*field));
|
||||
auto data = dynamic_cast<const STObject*> (
|
||||
node.peekAtPField (*field));
|
||||
|
||||
if (data)
|
||||
{
|
||||
const STAmount& takerGets = data->getFieldAmount (sfTakerGets);
|
||||
Currency const& currencyGets = takerGets.getCurrency ();
|
||||
Account const& issuerGets = takerGets.getIssuer ();
|
||||
|
||||
const STAmount& takerPays = data->getFieldAmount (sfTakerPays);
|
||||
Currency const& currencyPays = takerPays.getCurrency ();
|
||||
Account const& issuerPays = takerPays.getIssuer ();
|
||||
|
||||
// determine the OrderBook
|
||||
BookListeners::pointer book =
|
||||
getBookListeners (currencyPays, currencyGets, issuerPays, issuerGets);
|
||||
auto listeners = getBookListeners (
|
||||
{data->getFieldAmount (sfTakerGets).issue(),
|
||||
data->getFieldAmount (sfTakerPays).issue()});
|
||||
|
||||
if (book)
|
||||
book->publish (jvObj);
|
||||
if (listeners)
|
||||
listeners->publish (jvObj);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
WriteLog (lsINFO, OrderBookDB) << "Fields not found in OrderBookDB::processTxn";
|
||||
WriteLog (lsINFO, OrderBookDB)
|
||||
<< "Fields not found in OrderBookDB::processTxn";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
BookListeners::BookListeners ()
|
||||
{
|
||||
}
|
||||
|
||||
void BookListeners::addSubscriber (InfoSub::ref sub)
|
||||
{
|
||||
ScopedLockType sl (mLock);
|
||||
mListeners[sub->getSeq ()] = sub;
|
||||
}
|
||||
|
||||
void BookListeners::removeSubscriber (std::uint64_t seq)
|
||||
{
|
||||
ScopedLockType sl (mLock);
|
||||
mListeners.erase (seq);
|
||||
}
|
||||
|
||||
void BookListeners::publish (Json::Value const& jvObj)
|
||||
{
|
||||
Json::FastWriter jfwWriter;
|
||||
std::string sObj = jfwWriter.write (jvObj);
|
||||
|
||||
ScopedLockType sl (mLock);
|
||||
NetworkOPs::SubMapType::const_iterator it = mListeners.begin ();
|
||||
|
||||
while (it != mListeners.end ())
|
||||
{
|
||||
InfoSub::pointer p = it->second.lock ();
|
||||
|
||||
if (p)
|
||||
{
|
||||
p->send (jvObj, sObj, true);
|
||||
++it;
|
||||
}
|
||||
else
|
||||
it = mListeners.erase (it);
|
||||
}
|
||||
}
|
||||
|
||||
} // ripple
|
||||
|
||||
@@ -20,32 +20,10 @@
|
||||
#ifndef RIPPLE_ORDERBOOKDB_H_INCLUDED
|
||||
#define RIPPLE_ORDERBOOKDB_H_INCLUDED
|
||||
|
||||
#include <ripple/module/app/ledger/BookListeners.h>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
// VFALCO TODO Add Javadoc comment explaining what this class does
|
||||
class BookListeners
|
||||
{
|
||||
public:
|
||||
typedef std::shared_ptr<BookListeners> pointer;
|
||||
|
||||
BookListeners ();
|
||||
void addSubscriber (InfoSub::ref sub);
|
||||
void removeSubscriber (std::uint64_t sub);
|
||||
void publish (Json::Value const& jvObj);
|
||||
|
||||
private:
|
||||
typedef RippleRecursiveMutex LockType;
|
||||
typedef std::lock_guard <LockType> ScopedLockType;
|
||||
LockType mLock;
|
||||
|
||||
// VFALCO TODO Use a typedef for the uint64
|
||||
// Use a typedef for the container
|
||||
ripple::unordered_map<std::uint64_t, InfoSub::wptr> mListeners;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// VFALCO TODO Add Javadoc comment explaining what this class does
|
||||
class OrderBookDB
|
||||
: public beast::Stoppable
|
||||
, public beast::LeakChecked <OrderBookDB>
|
||||
@@ -57,36 +35,32 @@ public:
|
||||
void update (Ledger::pointer ledger);
|
||||
void invalidate ();
|
||||
|
||||
void addOrderBook(
|
||||
Currency const& takerPaysCurrency, Currency const& takerGetsCurrency,
|
||||
Account const& takerPaysIssuer, Account const& takerGetsIssuer);
|
||||
void addOrderBook(Book const&);
|
||||
|
||||
// return list of all orderbooks that want this issuerID and currencyID
|
||||
void getBooksByTakerPays (Account const& issuerID, Currency const& currencyID,
|
||||
std::vector<OrderBook::pointer>& bookRet);
|
||||
void getBooksByTakerGets (Account const& issuerID, Currency const& currencyID,
|
||||
std::vector<OrderBook::pointer>& bookRet);
|
||||
void getBooksByTakerPays (Issue const&, OrderBook::List&);
|
||||
void getBooksByTakerGets (Issue const&, OrderBook::List&);
|
||||
|
||||
bool isBookToXRP (Account const& issuerID, Currency const& currencyID);
|
||||
bool isBookToXRP (Issue const&);
|
||||
|
||||
BookListeners::pointer getBookListeners (Currency const& currencyPays, Currency const& currencyGets,
|
||||
Account const& issuerPays, Account const& issuerGets);
|
||||
|
||||
BookListeners::pointer makeBookListeners (Currency const& currencyPays, Currency const& currencyGets,
|
||||
Account const& issuerPays, Account const& issuerGets);
|
||||
BookListeners::pointer getBookListeners (Book const&);
|
||||
BookListeners::pointer makeBookListeners (Book const&);
|
||||
|
||||
// see if this txn effects any orderbook
|
||||
void processTxn (Ledger::ref ledger, const AcceptedLedgerTx& alTx, Json::Value const& jvObj);
|
||||
void processTxn (
|
||||
Ledger::ref ledger, const AcceptedLedgerTx& alTx,
|
||||
Json::Value const& jvObj);
|
||||
|
||||
typedef ripple::unordered_map <Issue, OrderBook::List> IssueToOrderBook;
|
||||
|
||||
private:
|
||||
typedef ripple::unordered_map <Issue, std::vector<OrderBook::pointer>>
|
||||
AssetToOrderBook;
|
||||
void rawAddBook(Book const&);
|
||||
|
||||
// by ci/ii
|
||||
AssetToOrderBook mSourceMap;
|
||||
IssueToOrderBook mSourceMap;
|
||||
|
||||
// by co/io
|
||||
AssetToOrderBook mDestMap;
|
||||
IssueToOrderBook mDestMap;
|
||||
|
||||
// does an order book to XRP exist
|
||||
ripple::unordered_set <Issue> mXRPBooks;
|
||||
@@ -101,7 +75,6 @@ private:
|
||||
BookToListenersMap mListeners;
|
||||
|
||||
std::uint32_t mSeq;
|
||||
|
||||
};
|
||||
|
||||
} // ripple
|
||||
|
||||
@@ -24,7 +24,8 @@ BookDirIterator::BookDirIterator(
|
||||
Currency const& currencyIn, Account const& issuerIn,
|
||||
Currency const& currencyOut, Account const& issuerOut)
|
||||
{
|
||||
mBase = Ledger::getBookBase(currencyIn, issuerIn, currencyOut, issuerOut);
|
||||
mBase = Ledger::getBookBase({{currencyIn, issuerIn},
|
||||
{currencyOut, issuerOut}});
|
||||
mEnd = Ledger::getQualityNext(mBase);
|
||||
mIndex = mBase;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -190,10 +190,7 @@ public:
|
||||
|
||||
virtual void getBookPage (
|
||||
Ledger::pointer lpLedger,
|
||||
Currency const& uTakerPaysCurrencyID,
|
||||
Account const& uTakerPaysIssuerID,
|
||||
Currency const& uTakerGetsCurrencyID,
|
||||
Account const& uTakerGetsIssuerID,
|
||||
Book const& book,
|
||||
Account const& uTakerID,
|
||||
bool const bProof,
|
||||
const unsigned int iLimit,
|
||||
@@ -232,7 +229,8 @@ public:
|
||||
|
||||
virtual bool shouldFetchPack (std::uint32_t seq) = 0;
|
||||
virtual void gotFetchPack (bool progress, std::uint32_t seq) = 0;
|
||||
virtual void addFetchPack (uint256 const& hash, std::shared_ptr< Blob >& data) = 0;
|
||||
virtual void addFetchPack (
|
||||
uint256 const& hash, std::shared_ptr< Blob >& data) = 0;
|
||||
virtual bool getFetchPack (uint256 const& hash, Blob& data) = 0;
|
||||
virtual int getFetchSize () = 0;
|
||||
virtual void sweepFetchPack () = 0;
|
||||
@@ -242,7 +240,8 @@ public:
|
||||
virtual void setStandAlone () = 0;
|
||||
virtual void setStateTimer () = 0;
|
||||
|
||||
virtual void newLCL (int proposers, int convergeTime, uint256 const& ledgerHash) = 0;
|
||||
virtual void newLCL (
|
||||
int proposers, int convergeTime, uint256 const& ledgerHash) = 0;
|
||||
// VFALCO TODO rename to setNeedNetworkLedger
|
||||
virtual void needNetworkLedger () = 0;
|
||||
virtual void clearNeedNetworkLedger () = 0;
|
||||
@@ -287,18 +286,29 @@ public:
|
||||
bool count, bool bAdmin) = 0;
|
||||
|
||||
// client information retrieval functions
|
||||
typedef std::vector< std::pair<Transaction::pointer, TransactionMetaSet::pointer> > AccountTxs;
|
||||
virtual AccountTxs getAccountTxs (const RippleAddress& account,
|
||||
std::int32_t minLedger, std::int32_t maxLedger, bool descending, std::uint32_t offset,
|
||||
int limit, bool bAdmin) = 0;
|
||||
typedef std::vector<
|
||||
std::pair<Transaction::pointer, TransactionMetaSet::pointer> >
|
||||
AccountTxs;
|
||||
|
||||
typedef std::vector< std::pair<Transaction::pointer, TransactionMetaSet::pointer> > TxsAccount;
|
||||
virtual TxsAccount getTxsAccount (const RippleAddress& account,
|
||||
std::int32_t minLedger, std::int32_t maxLedger, bool forward, Json::Value& token,
|
||||
int limit, bool bAdmin) = 0;
|
||||
virtual AccountTxs getAccountTxs (
|
||||
const RippleAddress& account,
|
||||
std::int32_t minLedger, std::int32_t maxLedger, bool descending,
|
||||
std::uint32_t offset, int limit, bool bAdmin) = 0;
|
||||
|
||||
typedef std::vector<
|
||||
std::pair<Transaction::pointer, TransactionMetaSet::pointer> >
|
||||
TxsAccount;
|
||||
|
||||
virtual TxsAccount getTxsAccount (
|
||||
const RippleAddress& account,
|
||||
std::int32_t minLedger, std::int32_t maxLedger, bool forward,
|
||||
Json::Value& token, int limit, bool bAdmin) = 0;
|
||||
|
||||
typedef std::tuple<std::string, std::string, std::uint32_t>
|
||||
txnMetaLedgerType;
|
||||
|
||||
typedef std::tuple<std::string, std::string, std::uint32_t> txnMetaLedgerType;
|
||||
typedef std::vector<txnMetaLedgerType> MetaTxsList;
|
||||
|
||||
virtual MetaTxsList getAccountTxsB (const RippleAddress& account,
|
||||
std::int32_t minLedger, std::int32_t maxLedger, bool descending,
|
||||
std::uint32_t offset, int limit, bool bAdmin) = 0;
|
||||
@@ -307,7 +317,8 @@ public:
|
||||
std::int32_t minLedger, std::int32_t maxLedger, bool forward,
|
||||
Json::Value& token, int limit, bool bAdmin) = 0;
|
||||
|
||||
virtual std::vector<RippleAddress> getLedgerAffectedAccounts (std::uint32_t ledgerSeq) = 0;
|
||||
virtual std::vector<RippleAddress> getLedgerAffectedAccounts (
|
||||
std::uint32_t ledgerSeq) = 0;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
|
||||
@@ -28,55 +28,53 @@ class OrderBook : beast::LeakChecked <OrderBook>
|
||||
public:
|
||||
typedef std::shared_ptr <OrderBook> pointer;
|
||||
typedef std::shared_ptr <OrderBook> const& ref;
|
||||
typedef std::vector<pointer> List;
|
||||
|
||||
public:
|
||||
/** Construct from a currency specification.
|
||||
|
||||
@param index ???
|
||||
@param currencyIn The base currency.
|
||||
@param currencyOut The destination currency.
|
||||
@param issuerIn The base issuer.
|
||||
@param issuerOut The destination issuer.
|
||||
@param book in and out currency/issuer pairs.
|
||||
*/
|
||||
// VFALCO NOTE what is the meaning of the index parameter?
|
||||
// VFALCO TODO Replace with Issue
|
||||
OrderBook (uint256 const& index,
|
||||
Currency const& currencyIn,
|
||||
Currency const& currencyOut,
|
||||
Account const& issuerIn,
|
||||
Account const& issuerOut);
|
||||
OrderBook (uint256 const& base, Book const& book)
|
||||
: mBookBase(base), mBook(book)
|
||||
{
|
||||
}
|
||||
|
||||
uint256 const& getBookBase () const
|
||||
{
|
||||
return mBookBase;
|
||||
}
|
||||
|
||||
Book const& book() const
|
||||
{
|
||||
return mBook;
|
||||
}
|
||||
|
||||
Currency const& getCurrencyIn () const
|
||||
{
|
||||
return mCurrencyIn;
|
||||
return mBook.in.currency;
|
||||
}
|
||||
|
||||
Currency const& getCurrencyOut () const
|
||||
{
|
||||
return mCurrencyOut;
|
||||
return mBook.out.currency;
|
||||
}
|
||||
|
||||
Account const& getIssuerIn () const
|
||||
{
|
||||
return mIssuerIn;
|
||||
return mBook.in.account;
|
||||
}
|
||||
|
||||
Account const& getIssuerOut () const
|
||||
{
|
||||
return mIssuerOut;
|
||||
return mBook.out.account;
|
||||
}
|
||||
|
||||
private:
|
||||
uint256 const mBookBase;
|
||||
Currency const mCurrencyIn;
|
||||
Currency const mCurrencyOut;
|
||||
Account const mIssuerIn;
|
||||
Account const mIssuerOut;
|
||||
Book const mBook;
|
||||
};
|
||||
|
||||
} // ripple
|
||||
|
||||
@@ -71,10 +71,9 @@ TER nodeAdvance (
|
||||
{
|
||||
// Need to initialize current node.
|
||||
|
||||
node.currentDirectory_.copyFrom(Ledger::getBookBase (
|
||||
previousNode.currency_, previousNode.issuer_,
|
||||
node.currency_,
|
||||
node.issuer_));
|
||||
node.currentDirectory_.copyFrom(Ledger::getBookBase ({
|
||||
{previousNode.currency_, previousNode.issuer_},
|
||||
{node.currency_, node.issuer_}}));
|
||||
node.nextDirectory_.copyFrom(
|
||||
Ledger::getQualityNext (node.currentDirectory_));
|
||||
|
||||
|
||||
@@ -787,7 +787,7 @@ void Pathfinder::addLink(
|
||||
{ // add order books
|
||||
if (addFlags & afOB_XRP)
|
||||
{ // to XRP only
|
||||
if (!bOnXRP && getApp().getOrderBookDB().isBookToXRP(uEndIssuer, uEndCurrency))
|
||||
if (!bOnXRP && getApp().getOrderBookDB().isBookToXRP({uEndCurrency, uEndIssuer}))
|
||||
{
|
||||
STPathElement pathElement(
|
||||
STPathElement::typeCurrency,
|
||||
@@ -799,7 +799,7 @@ void Pathfinder::addLink(
|
||||
{
|
||||
bool bDestOnly = (addFlags & afOB_LAST) != 0;
|
||||
std::vector<OrderBook::pointer> books;
|
||||
getApp().getOrderBookDB().getBooksByTakerPays(uEndIssuer, uEndCurrency, books);
|
||||
getApp().getOrderBookDB().getBooksByTakerPays({uEndCurrency, uEndIssuer}, books);
|
||||
WriteLog (lsTRACE, Pathfinder) << books.size() << " books found from this currency/issuer";
|
||||
BOOST_FOREACH(OrderBook::ref book, books)
|
||||
{
|
||||
|
||||
@@ -442,8 +442,8 @@ CreateOffer::doApply ()
|
||||
view.ownerCountAdjust (mTxnAccountID, 1, sleCreator);
|
||||
|
||||
uint256 const uBookBase (Ledger::getBookBase (
|
||||
uPaysCurrency, uPaysIssuerID,
|
||||
uGetsCurrency, uGetsIssuerID));
|
||||
{{uPaysCurrency, uPaysIssuerID},
|
||||
{uGetsCurrency, uGetsIssuerID}}));
|
||||
|
||||
if (m_journal.debug) m_journal.debug <<
|
||||
"adding to book: " << to_string (uBookBase) <<
|
||||
|
||||
@@ -62,7 +62,8 @@ Resource::Consumer& InfoSub::getConsumer()
|
||||
return m_consumer;
|
||||
}
|
||||
|
||||
void InfoSub::send (const Json::Value& jvObj, const std::string& sObj, bool broadcast)
|
||||
void InfoSub::send (
|
||||
const Json::Value& jvObj, const std::string& sObj, bool broadcast)
|
||||
{
|
||||
send (jvObj, broadcast);
|
||||
}
|
||||
@@ -76,7 +77,8 @@ void InfoSub::onSendEmpty ()
|
||||
{
|
||||
}
|
||||
|
||||
void InfoSub::insertSubAccountInfo (RippleAddress addr, std::uint32_t uLedgerIndex)
|
||||
void InfoSub::insertSubAccountInfo (
|
||||
RippleAddress addr, std::uint32_t uLedgerIndex)
|
||||
{
|
||||
ScopedLockType sl (mLock);
|
||||
|
||||
|
||||
@@ -63,30 +63,19 @@ public:
|
||||
bool rt) = 0;
|
||||
|
||||
// VFALCO TODO Document the bool return value
|
||||
virtual bool subLedger (ref ispListener,
|
||||
Json::Value& jvResult) = 0;
|
||||
|
||||
virtual bool subLedger (ref ispListener, Json::Value& jvResult) = 0;
|
||||
virtual bool unsubLedger (std::uint64_t uListener) = 0;
|
||||
|
||||
virtual bool subServer (ref ispListener,
|
||||
Json::Value& jvResult) = 0;
|
||||
|
||||
virtual bool subServer (ref ispListener, Json::Value& jvResult) = 0;
|
||||
virtual bool unsubServer (std::uint64_t uListener) = 0;
|
||||
|
||||
virtual bool subBook (ref ispListener,
|
||||
Currency const& currencyPays, Currency const& currencyGets,
|
||||
Account const& issuerPays, Account const& issuerGets) = 0;
|
||||
|
||||
virtual bool unsubBook (std::uint64_t uListener,
|
||||
Currency const& currencyPays, Currency const& currencyGets,
|
||||
Account const& issuerPays, Account const& issuerGets) = 0;
|
||||
virtual bool subBook (ref ispListener, Book const&) = 0;
|
||||
virtual bool unsubBook (std::uint64_t uListener, Book const&) = 0;
|
||||
|
||||
virtual bool subTransactions (ref ispListener) = 0;
|
||||
|
||||
virtual bool unsubTransactions (std::uint64_t uListener) = 0;
|
||||
|
||||
virtual bool subRTTransactions (ref ispListener) = 0;
|
||||
|
||||
virtual bool unsubRTTransactions (std::uint64_t uListener) = 0;
|
||||
|
||||
// VFALCO TODO Remove
|
||||
@@ -94,7 +83,6 @@ public:
|
||||
// "pushes" subscription data to a particular URL.
|
||||
//
|
||||
virtual pointer findRpcSub (const std::string& strUrl) = 0;
|
||||
|
||||
virtual pointer addRpcSub (const std::string& strUrl, ref rspEntry) = 0;
|
||||
};
|
||||
|
||||
@@ -108,7 +96,8 @@ public:
|
||||
virtual void send (const Json::Value & jvObj, bool broadcast) = 0;
|
||||
|
||||
// VFALCO NOTE Why is this virtual?
|
||||
virtual void send (const Json::Value & jvObj, const std::string & sObj, bool broadcast);
|
||||
virtual void send (
|
||||
const Json::Value & jvObj, const std::string & sObj, bool broadcast);
|
||||
|
||||
std::uint64_t getSeq ();
|
||||
|
||||
|
||||
@@ -161,9 +161,11 @@ Json::Value doBookOffers (RPC::Context& context)
|
||||
return RPC::make_error (rpcBAD_MARKET);
|
||||
}
|
||||
|
||||
if (context.params_.isMember ("limit") && ! context.params_ ["limit"].isIntegral())
|
||||
return RPC::expected_field_error (
|
||||
"limit", "integer");
|
||||
if (context.params_.isMember ("limit") &&
|
||||
!context.params_ ["limit"].isIntegral())
|
||||
{
|
||||
return RPC::expected_field_error ("limit", "integer");
|
||||
}
|
||||
|
||||
unsigned int const iLimit (context.params_.isMember ("limit")
|
||||
? context.params_ ["limit"].asUInt ()
|
||||
@@ -175,9 +177,10 @@ Json::Value doBookOffers (RPC::Context& context)
|
||||
? context.params_["marker"]
|
||||
: Json::Value (Json::nullValue));
|
||||
|
||||
context.netOps_.getBookPage (lpLedger, pay_currency, pay_issuer,
|
||||
get_currency, get_issuer, raTakerID.getAccountID (),
|
||||
bProof, iLimit, jvMarker, jvResult);
|
||||
context.netOps_.getBookPage (
|
||||
lpLedger,
|
||||
{{pay_currency, pay_issuer}, {get_currency, get_issuer}},
|
||||
raTakerID.getAccountID (), bProof, iLimit, jvMarker, jvResult);
|
||||
|
||||
context.loadType_ = Resource::feeMediumBurdenRPC;
|
||||
|
||||
|
||||
@@ -27,14 +27,16 @@ Json::Value doSubscribe (RPC::Context& context)
|
||||
|
||||
InfoSub::pointer ispSub;
|
||||
Json::Value jvResult (Json::objectValue);
|
||||
std::uint32_t uLedgerIndex = context.params_.isMember (jss::ledger_index) && context.params_[jss::ledger_index].isNumeric ()
|
||||
std::uint32_t uLedgerIndex = context.params_.isMember (jss::ledger_index)
|
||||
&& context.params_[jss::ledger_index].isNumeric ()
|
||||
? context.params_[jss::ledger_index].asUInt ()
|
||||
: 0;
|
||||
|
||||
if (!context.infoSub_ && !context.params_.isMember ("url"))
|
||||
{
|
||||
// Must be a JSON-RPC call.
|
||||
WriteLog (lsINFO, RPCHandler) << boost::str (boost::format ("doSubscribe: RPC subscribe requires a url"));
|
||||
WriteLog (lsINFO, RPCHandler)
|
||||
<< "doSubscribe: RPC subscribe requires a url";
|
||||
|
||||
return rpcError (rpcINVALID_PARAMS);
|
||||
}
|
||||
@@ -45,8 +47,10 @@ Json::Value doSubscribe (RPC::Context& context)
|
||||
return rpcError (rpcNO_PERMISSION);
|
||||
|
||||
std::string strUrl = context.params_["url"].asString ();
|
||||
std::string strUsername = context.params_.isMember ("url_username") ? context.params_["url_username"].asString () : "";
|
||||
std::string strPassword = context.params_.isMember ("url_password") ? context.params_["url_password"].asString () : "";
|
||||
std::string strUsername = context.params_.isMember ("url_username") ?
|
||||
context.params_["url_username"].asString () : "";
|
||||
std::string strPassword = context.params_.isMember ("url_password") ?
|
||||
context.params_["url_password"].asString () : "";
|
||||
|
||||
// DEPRECATED
|
||||
if (context.params_.isMember ("username"))
|
||||
@@ -60,16 +64,19 @@ Json::Value doSubscribe (RPC::Context& context)
|
||||
|
||||
if (!ispSub)
|
||||
{
|
||||
WriteLog (lsDEBUG, RPCHandler) << boost::str (boost::format ("doSubscribe: building: %s") % strUrl);
|
||||
WriteLog (lsDEBUG, RPCHandler)
|
||||
<< "doSubscribe: building: " << strUrl;
|
||||
|
||||
RPCSub::pointer rspSub = RPCSub::New (getApp ().getOPs (),
|
||||
getApp ().getIOService (), getApp ().getJobQueue (),
|
||||
strUrl, strUsername, strPassword);
|
||||
ispSub = context.netOps_.addRpcSub (strUrl, std::dynamic_pointer_cast<InfoSub> (rspSub));
|
||||
ispSub = context.netOps_.addRpcSub (
|
||||
strUrl, std::dynamic_pointer_cast<InfoSub> (rspSub));
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteLog (lsTRACE, RPCHandler) << boost::str (boost::format ("doSubscribe: reusing: %s") % strUrl);
|
||||
WriteLog (lsTRACE, RPCHandler)
|
||||
<< "doSubscribe: reusing: " << strUrl;
|
||||
|
||||
if (context.params_.isMember ("username"))
|
||||
dynamic_cast<RPCSub*> (&*ispSub)->setUsername (strUsername);
|
||||
@@ -88,17 +95,18 @@ Json::Value doSubscribe (RPC::Context& context)
|
||||
}
|
||||
else if (!context.params_["streams"].isArray ())
|
||||
{
|
||||
WriteLog (lsINFO, RPCHandler) << boost::str (boost::format ("doSubscribe: streams requires an array."));
|
||||
WriteLog (lsINFO, RPCHandler)
|
||||
<< "doSubscribe: streams requires an array.";
|
||||
|
||||
return rpcError (rpcINVALID_PARAMS);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (Json::Value::iterator it = context.params_["streams"].begin (); it != context.params_["streams"].end (); it++)
|
||||
for (auto& it: context.params_["streams"])
|
||||
{
|
||||
if ((*it).isString ())
|
||||
if (it.isString ())
|
||||
{
|
||||
std::string streamName = (*it).asString ();
|
||||
std::string streamName = it.asString ();
|
||||
|
||||
if (streamName == "server")
|
||||
{
|
||||
@@ -129,9 +137,9 @@ Json::Value doSubscribe (RPC::Context& context)
|
||||
}
|
||||
}
|
||||
|
||||
std::string strAccountsProposed = context.params_.isMember ("accounts_proposed")
|
||||
? "accounts_proposed"
|
||||
: "rt_accounts"; // DEPRECATED
|
||||
std::string strAccountsProposed =
|
||||
context.params_.isMember ("accounts_proposed")
|
||||
? "accounts_proposed" : "rt_accounts"; // DEPRECATED
|
||||
|
||||
if (!context.params_.isMember (strAccountsProposed))
|
||||
{
|
||||
@@ -142,16 +150,12 @@ Json::Value doSubscribe (RPC::Context& context)
|
||||
}
|
||||
else
|
||||
{
|
||||
ripple::unordered_set<RippleAddress> usnaAccoundIds = RPC::parseAccountIds (context.params_[strAccountsProposed]);
|
||||
auto ids = RPC::parseAccountIds (context.params_[strAccountsProposed]);
|
||||
|
||||
if (usnaAccoundIds.empty ())
|
||||
{
|
||||
if (ids.empty ())
|
||||
jvResult[jss::error] = "malformedAccount";
|
||||
}
|
||||
else
|
||||
{
|
||||
context.netOps_.subAccount (ispSub, usnaAccoundIds, uLedgerIndex, true);
|
||||
}
|
||||
context.netOps_.subAccount (ispSub, ids, uLedgerIndex, true);
|
||||
}
|
||||
|
||||
if (!context.params_.isMember ("accounts"))
|
||||
@@ -163,17 +167,17 @@ Json::Value doSubscribe (RPC::Context& context)
|
||||
}
|
||||
else
|
||||
{
|
||||
ripple::unordered_set<RippleAddress> usnaAccoundIds = RPC::parseAccountIds (context.params_["accounts"]);
|
||||
auto ids = RPC::parseAccountIds (context.params_["accounts"]);
|
||||
|
||||
if (usnaAccoundIds.empty ())
|
||||
if (ids.empty ())
|
||||
{
|
||||
jvResult[jss::error] = "malformedAccount";
|
||||
}
|
||||
else
|
||||
{
|
||||
context.netOps_.subAccount (ispSub, usnaAccoundIds, uLedgerIndex, false);
|
||||
|
||||
WriteLog (lsDEBUG, RPCHandler) << boost::str (boost::format ("doSubscribe: accounts: %d") % usnaAccoundIds.size ());
|
||||
context.netOps_.subAccount (ispSub, ids, uLedgerIndex, false);
|
||||
WriteLog (lsDEBUG, RPCHandler)
|
||||
<< "doSubscribe: accounts: " << ids.size ();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -187,34 +191,32 @@ Json::Value doSubscribe (RPC::Context& context)
|
||||
}
|
||||
else
|
||||
{
|
||||
for (Json::Value::iterator it = context.params_["books"].begin (); it != context.params_["books"].end (); it++)
|
||||
for (auto& j: context.params_["books"])
|
||||
{
|
||||
Json::Value& jvSubRequest = *it;
|
||||
|
||||
if (!jvSubRequest.isObject ()
|
||||
|| !jvSubRequest.isMember (jss::taker_pays)
|
||||
|| !jvSubRequest.isMember (jss::taker_gets)
|
||||
|| !jvSubRequest[jss::taker_pays].isObject ()
|
||||
|| !jvSubRequest[jss::taker_gets].isObject ())
|
||||
if (!j.isObject ()
|
||||
|| !j.isMember (jss::taker_pays)
|
||||
|| !j.isMember (jss::taker_gets)
|
||||
|| !j[jss::taker_pays].isObject ()
|
||||
|| !j[jss::taker_gets].isObject ())
|
||||
return rpcError (rpcINVALID_PARAMS);
|
||||
|
||||
// VFALCO TODO Use Issue here
|
||||
Currency pay_currency;
|
||||
Account pay_issuer;
|
||||
Currency get_currency;
|
||||
Account get_issuer;
|
||||
Book book;
|
||||
bool bBoth =
|
||||
(j.isMember ("both") && j["both"].asBool ()) ||
|
||||
(j.isMember ("both_sides") && j["both_sides"].asBool ());
|
||||
bool bSnapshot =
|
||||
(j.isMember ("snapshot") && j["snapshot"].asBool ()) ||
|
||||
(j.isMember ("state_now") && j["state_now"].asBool ());
|
||||
// TODO(tom): both_sides and state_now are apparently deprecated...
|
||||
// where is this documented?
|
||||
|
||||
bool bBoth = (jvSubRequest.isMember ("both") && jvSubRequest["both"].asBool ())
|
||||
|| (jvSubRequest.isMember ("both_sides") && jvSubRequest["both_sides"].asBool ()); // DEPRECATED
|
||||
bool bSnapshot = (jvSubRequest.isMember ("snapshot") && jvSubRequest["snapshot"].asBool ())
|
||||
|| (jvSubRequest.isMember ("state_now") && jvSubRequest["state_now"].asBool ()); // DEPRECATED
|
||||
|
||||
Json::Value taker_pays = jvSubRequest[jss::taker_pays];
|
||||
Json::Value taker_gets = jvSubRequest[jss::taker_gets];
|
||||
Json::Value taker_pays = j[jss::taker_pays];
|
||||
Json::Value taker_gets = j[jss::taker_gets];
|
||||
|
||||
// Parse mandatory currency.
|
||||
if (!taker_pays.isMember (jss::currency)
|
||||
|| !to_currency (pay_currency, taker_pays[jss::currency].asString ()))
|
||||
|| !to_currency (book.in.currency,
|
||||
taker_pays[jss::currency].asString ()))
|
||||
{
|
||||
WriteLog (lsINFO, RPCHandler) << "Bad taker_pays currency.";
|
||||
|
||||
@@ -223,10 +225,11 @@ Json::Value doSubscribe (RPC::Context& context)
|
||||
// Parse optional issuer.
|
||||
else if (((taker_pays.isMember (jss::issuer))
|
||||
&& (!taker_pays[jss::issuer].isString ()
|
||||
|| !to_issuer (pay_issuer, taker_pays[jss::issuer].asString ())))
|
||||
|| !to_issuer (book.in.account,
|
||||
taker_pays[jss::issuer].asString ())))
|
||||
// Don't allow illegal issuers.
|
||||
|| (!pay_currency != !pay_issuer)
|
||||
|| noAccount() == pay_issuer)
|
||||
|| (!book.in.currency != !book.in.account)
|
||||
|| noAccount() == book.in.account)
|
||||
{
|
||||
WriteLog (lsINFO, RPCHandler) << "Bad taker_pays issuer.";
|
||||
|
||||
@@ -235,7 +238,8 @@ Json::Value doSubscribe (RPC::Context& context)
|
||||
|
||||
// Parse mandatory currency.
|
||||
if (!taker_gets.isMember (jss::currency)
|
||||
|| !to_currency (get_currency, taker_gets[jss::currency].asString ()))
|
||||
|| !to_currency (book.out.currency,
|
||||
taker_gets[jss::currency].asString ()))
|
||||
{
|
||||
WriteLog (lsINFO, RPCHandler) << "Bad taker_pays currency.";
|
||||
|
||||
@@ -244,18 +248,19 @@ Json::Value doSubscribe (RPC::Context& context)
|
||||
// Parse optional issuer.
|
||||
else if (((taker_gets.isMember (jss::issuer))
|
||||
&& (!taker_gets[jss::issuer].isString ()
|
||||
|| !to_issuer (get_issuer, taker_gets[jss::issuer].asString ())))
|
||||
|| !to_issuer (book.out.account,
|
||||
taker_gets[jss::issuer].asString ())))
|
||||
// Don't allow illegal issuers.
|
||||
|| (!get_currency != !get_issuer)
|
||||
|| noAccount() == get_issuer)
|
||||
|| (!book.out.currency != !book.out.account)
|
||||
|| noAccount() == book.out.account)
|
||||
{
|
||||
WriteLog (lsINFO, RPCHandler) << "Bad taker_gets issuer.";
|
||||
|
||||
return rpcError (rpcDST_ISR_MALFORMED);
|
||||
}
|
||||
|
||||
if (pay_currency == get_currency
|
||||
&& pay_issuer == get_issuer)
|
||||
if (book.in.currency == book.out.currency
|
||||
&& book.in.account == book.out.account)
|
||||
{
|
||||
WriteLog (lsINFO, RPCHandler) << "taker_gets same as taker_pays.";
|
||||
|
||||
@@ -264,26 +269,21 @@ Json::Value doSubscribe (RPC::Context& context)
|
||||
|
||||
RippleAddress raTakerID;
|
||||
|
||||
if (!jvSubRequest.isMember ("taker"))
|
||||
{
|
||||
if (!j.isMember ("taker"))
|
||||
raTakerID.setAccountID (noAccount());
|
||||
}
|
||||
else if (!raTakerID.setAccountID (jvSubRequest["taker"].asString ()))
|
||||
{
|
||||
else if (!raTakerID.setAccountID (j["taker"].asString ()))
|
||||
return rpcError (rpcBAD_ISSUER);
|
||||
}
|
||||
|
||||
if (!Ledger::isValidBook (pay_currency, pay_issuer, get_currency, get_issuer))
|
||||
if (!isConsistent (book))
|
||||
{
|
||||
WriteLog (lsWARNING, RPCHandler) << "Bad market: " <<
|
||||
pay_currency << ":" << pay_issuer << " -> " <<
|
||||
get_currency << ":" << get_issuer;
|
||||
WriteLog (lsWARNING, RPCHandler) << "Bad market: " << book;
|
||||
return rpcError (rpcBAD_MARKET);
|
||||
}
|
||||
|
||||
context.netOps_.subBook (ispSub, pay_currency, get_currency, pay_issuer, get_issuer);
|
||||
context.netOps_.subBook (ispSub, book);
|
||||
|
||||
if (bBoth) context.netOps_.subBook (ispSub, get_currency, pay_currency, get_issuer, pay_issuer);
|
||||
if (bBoth)
|
||||
context.netOps_.subBook (ispSub, book);
|
||||
|
||||
if (bSnapshot)
|
||||
{
|
||||
@@ -294,7 +294,8 @@ Json::Value doSubscribe (RPC::Context& context)
|
||||
}
|
||||
|
||||
context.loadType_ = Resource::feeMediumBurdenRPC;
|
||||
Ledger::pointer lpLedger = getApp().getLedgerMaster ().getPublishedLedger ();
|
||||
auto lpLedger = getApp().getLedgerMaster ().
|
||||
getPublishedLedger ();
|
||||
if (lpLedger)
|
||||
{
|
||||
const Json::Value jvMarker = Json::Value (Json::nullValue);
|
||||
@@ -304,17 +305,25 @@ Json::Value doSubscribe (RPC::Context& context)
|
||||
Json::Value jvBids (Json::objectValue);
|
||||
Json::Value jvAsks (Json::objectValue);
|
||||
|
||||
context.netOps_.getBookPage (lpLedger, pay_currency, pay_issuer, get_currency, get_issuer, raTakerID.getAccountID (), false, 0, jvMarker, jvBids);
|
||||
context.netOps_.getBookPage (
|
||||
lpLedger, book, raTakerID.getAccountID (), false, 0,
|
||||
jvMarker, jvBids);
|
||||
|
||||
if (jvBids.isMember (jss::offers)) jvResult[jss::bids] = jvBids[jss::offers];
|
||||
if (jvBids.isMember (jss::offers))
|
||||
jvResult[jss::bids] = jvBids[jss::offers];
|
||||
|
||||
context.netOps_.getBookPage (lpLedger, get_currency, get_issuer, pay_currency, pay_issuer, raTakerID.getAccountID (), false, 0, jvMarker, jvAsks);
|
||||
context.netOps_.getBookPage (
|
||||
lpLedger, book, raTakerID.getAccountID (),
|
||||
false, 0, jvMarker, jvAsks);
|
||||
|
||||
if (jvAsks.isMember (jss::offers)) jvResult[jss::asks] = jvAsks[jss::offers];
|
||||
if (jvAsks.isMember (jss::offers))
|
||||
jvResult[jss::asks] = jvAsks[jss::offers];
|
||||
}
|
||||
else
|
||||
{
|
||||
context.netOps_.getBookPage (lpLedger, pay_currency, pay_issuer, get_currency, get_issuer, raTakerID.getAccountID (), false, 0, jvMarker, jvResult);
|
||||
context.netOps_.getBookPage (
|
||||
lpLedger, book, raTakerID.getAccountID (), false, 0,
|
||||
jvMarker, jvResult);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -203,18 +203,11 @@ Json::Value doUnsubscribe (RPC::Context& context)
|
||||
return rpcError (rpcBAD_MARKET);
|
||||
}
|
||||
|
||||
context.netOps_.unsubBook (
|
||||
ispSub->getSeq (),
|
||||
pay_currency, get_currency,
|
||||
pay_issuer, get_issuer);
|
||||
Book book{{pay_currency, pay_issuer}, {get_currency, get_issuer}};
|
||||
context.netOps_.unsubBook (ispSub->getSeq (), book);
|
||||
|
||||
if (bBoth)
|
||||
{
|
||||
context.netOps_.unsubBook (
|
||||
ispSub->getSeq (),
|
||||
get_currency, pay_currency,
|
||||
get_issuer, pay_issuer);
|
||||
}
|
||||
context.netOps_.unsubBook (ispSub->getSeq (), book);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -66,6 +66,13 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
template <bool ByValue>
|
||||
bool isConsistent(BookType<ByValue> const& book)
|
||||
{
|
||||
return isConsistent(book.in) && isConsistent (book.out)
|
||||
&& book.in != book.out;
|
||||
}
|
||||
|
||||
template <bool ByValue>
|
||||
std::string to_string (BookType<ByValue> const& book)
|
||||
{
|
||||
|
||||
@@ -83,6 +83,13 @@ bool isConsistent(IssueType<ByValue> const& ac)
|
||||
return isXRP (ac.currency) == isXRP (ac.account);
|
||||
}
|
||||
|
||||
template <bool ByValue>
|
||||
bool isXRP(IssueType<ByValue> const& ac)
|
||||
{
|
||||
// Assumes that isConsistent() is true.
|
||||
return isXRP (ac.currency);
|
||||
}
|
||||
|
||||
template <bool ByValue>
|
||||
std::string to_string (IssueType<ByValue> const& ac)
|
||||
{
|
||||
|
||||
@@ -32,7 +32,6 @@
|
||||
#include <ripple/module/app/misc/ProofOfWorkFactory.h>
|
||||
|
||||
#include <ripple/module/app/peers/PeerSet.cpp>
|
||||
#include <ripple/module/app/misc/OrderBook.cpp>
|
||||
#include <ripple/module/app/misc/ProofOfWorkFactory.cpp>
|
||||
#include <ripple/module/app/misc/ProofOfWork.cpp>
|
||||
#include <ripple/module/app/misc/SerializedTransaction.cpp>
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
#include <ripple/module/app/ledger/LedgerProposal.cpp>
|
||||
#include <ripple/module/app/main/LoadManager.cpp>
|
||||
#include <ripple/module/app/misc/NicknameState.cpp>
|
||||
#include <ripple/module/app/ledger/BookListeners.cpp>
|
||||
#include <ripple/module/app/ledger/OrderBookDB.cpp>
|
||||
|
||||
#include <ripple/module/app/data/Database.cpp>
|
||||
|
||||
Reference in New Issue
Block a user