Use Books in Ledger.

This commit is contained in:
Tom Ritchford
2014-07-12 12:53:11 -04:00
committed by Vinnie Falco
parent 3e9c702c47
commit 6014b13234
25 changed files with 854 additions and 837 deletions

View File

@@ -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>

View File

@@ -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>

View File

@@ -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))
{
}

View 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

View File

@@ -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

View File

@@ -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}});
}
}

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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;
//--------------------------------------------------------------------------
//

View File

@@ -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

View File

@@ -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_));

View File

@@ -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)
{

View File

@@ -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) <<

View File

@@ -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);

View File

@@ -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 ();

View File

@@ -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;

View File

@@ -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);
}
}
}

View File

@@ -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);
}
}

View File

@@ -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)
{

View File

@@ -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)
{

View File

@@ -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>

View File

@@ -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>