first draft

This commit is contained in:
jed
2013-02-05 13:04:38 -08:00
parent 62f6d030c6
commit eb27240610
9 changed files with 200 additions and 20 deletions

View File

@@ -1447,6 +1447,20 @@ void NetworkOPs::unsubAccount(InfoSub* ispListener, const boost::unordered_set<R
} }
} }
bool NetworkOPs::subBook(InfoSub* ispListener, uint160 currencyIn, uint160 currencyOut, uint160 issuerIn, uint160 issuerOut)
{
BookListeners::pointer listeners=theApp->getOrderBookDB().makeBookListeners(currencyIn, currencyOut, issuerIn, issuerOut);
if(listeners) listeners->addSubscriber(ispListener);
return(true);
}
bool NetworkOPs::unsubBook(InfoSub* ispListener, uint160 currencyIn, uint160 currencyOut, uint160 issuerIn, uint160 issuerOut)
{
BookListeners::pointer listeners=theApp->getOrderBookDB().getBookListeners(currencyIn, currencyOut, issuerIn, issuerOut);
if(listeners) listeners->removeSubscriber(ispListener);
return(true);
}
void NetworkOPs::newLCL(int proposers, int convergeTime, const uint256& ledgerHash) void NetworkOPs::newLCL(int proposers, int convergeTime, const uint256& ledgerHash)
{ {
assert(convergeTime); assert(convergeTime);

View File

@@ -284,6 +284,9 @@ public:
bool subServer(InfoSub* ispListener, Json::Value& jvResult); bool subServer(InfoSub* ispListener, Json::Value& jvResult);
bool unsubServer(InfoSub* ispListener); bool unsubServer(InfoSub* ispListener);
bool subBook(InfoSub* ispListener, uint160 currencyIn, uint160 currencyOut, uint160 issuerIn, uint160 issuerOut);
bool unsubBook(InfoSub* ispListener, uint160 currencyIn, uint160 currencyOut, uint160 issuerIn, uint160 issuerOut);
bool subTransactions(InfoSub* ispListener); bool subTransactions(InfoSub* ispListener);
bool unsubTransactions(InfoSub* ispListener); bool unsubTransactions(InfoSub* ispListener);

View File

@@ -20,4 +20,6 @@ OrderBook::OrderBook(SerializedLedgerEntry::pointer ledgerEntry)
mBookBase=Ledger::getBookBase(mCurrencyOut,mIssuerOut,mCurrencyIn,mIssuerIn); mBookBase=Ledger::getBookBase(mCurrencyOut,mIssuerOut,mCurrencyIn,mIssuerIn);
} }
// vim:ts=4 // vim:ts=4

View File

@@ -14,8 +14,6 @@ class OrderBook
uint160 mIssuerIn; uint160 mIssuerIn;
uint160 mIssuerOut; uint160 mIssuerOut;
boost::unordered_set<InfoSub*> mListeners;
//SerializedLedgerEntry::pointer mLedgerEntry; //SerializedLedgerEntry::pointer mLedgerEntry;
OrderBook(SerializedLedgerEntry::pointer ledgerEntry); // For accounts in a ledger OrderBook(SerializedLedgerEntry::pointer ledgerEntry); // For accounts in a ledger
public: public:
@@ -34,9 +32,6 @@ public:
// looks through the best offers to see how much it would cost to take the given amount // looks through the best offers to see how much it would cost to take the given amount
STAmount& getTakePrice(STAmount& takeAmount); STAmount& getTakePrice(STAmount& takeAmount);
void addSubscriber(InfoSub* sub);
void removeSubscriber(InfoSub* sub);
}; };
// vim:ts=4 // vim:ts=4

View File

@@ -2,6 +2,7 @@
#include "Log.h" #include "Log.h"
#include <boost/foreach.hpp> #include <boost/foreach.hpp>
SETUP_LOG();
OrderBookDB::OrderBookDB() OrderBookDB::OrderBookDB()
{ {
@@ -11,6 +12,10 @@ OrderBookDB::OrderBookDB()
// TODO: this would be way faster if we could just look under the order dirs // TODO: this would be way faster if we could just look under the order dirs
void OrderBookDB::setup(Ledger::pointer ledger) void OrderBookDB::setup(Ledger::pointer ledger)
{ {
mXRPOrders.clear();
mIssuerMap.clear();
mKnownMap.clear();
// walk through the entire ledger looking for orderbook entries // walk through the entire ledger looking for orderbook entries
uint256 currentIndex=ledger->getFirstLedgerIndex(); uint256 currentIndex=ledger->getFirstLedgerIndex();
while(currentIndex.isNonZero()) while(currentIndex.isNonZero())
@@ -60,9 +65,37 @@ void OrderBookDB::getBooks(const uint160& issuerID, const uint160& currencyID, s
} }
} }
OrderBook::pointer OrderBookDB::getBook(uint160 mCurrencyIn, uint160 mCurrencyOut, uint160 mIssuerIn, uint160 mIssuerOut) BookListeners::pointer OrderBookDB::makeBookListeners(uint160 currencyIn, uint160 currencyOut, uint160 issuerIn, uint160 issuerOut)
{ {
BookListeners::pointer ret=getBookListeners(currencyIn, currencyOut, issuerIn, issuerOut);
if(!ret)
{
ret=BookListeners::pointer(new BookListeners);
mListeners[issuerIn][issuerOut][currencyIn][currencyOut]=ret;
}
return(ret);
}
BookListeners::pointer OrderBookDB::getBookListeners(uint160 currencyIn, uint160 currencyOut, uint160 issuerIn, uint160 issuerOut)
{
std::map<uint160, std::map<uint160, std::map<uint160, std::map<uint160, BookListeners::pointer> > > >::iterator it0=mListeners.find(issuerIn);
if(it0 != mListeners.end())
{
std::map<uint160, std::map<uint160, std::map<uint160, BookListeners::pointer> > >::iterator it1=(*it0).second.find(issuerOut);
if(it1 != (*it0).second.end())
{
std::map<uint160, std::map<uint160, BookListeners::pointer> >::iterator it2=(*it1).second.find(currencyIn);
if(it2 != (*it1).second.end())
{
std::map<uint160, BookListeners::pointer>::iterator it3=(*it2).second.find(currencyOut);
if(it3 != (*it2).second.end())
{
return( (*it3).second );
}
}
}
}
return(BookListeners::pointer());
} }
/* /*
@@ -80,19 +113,101 @@ OrderBook::pointer OrderBookDB::getBook(uint160 mCurrencyIn, uint160 mCurrencyOu
"value" : "1" "value" : "1"
} }
} }
}*/ }
"ModifiedNode" : {
"FinalFields" : {
"Account" : "rHTxKLzRbniScyQFGMb3NodmxA848W8dKM",
"BookDirectory" : "407AF8FFDE71114B1981574FDDA9B0334572D56FC579735B4B0BD7A625405555",
"BookNode" : "0000000000000000",
"Flags" : 0,
"OwnerNode" : "0000000000000000",
"Sequence" : 32,
"TakerGets" : "149900000000",
"TakerPays" : {
"currency" : "USD",
"issuer" : "r9vbV3EHvXWjSkeQ6CAcYVPGeq7TuiXY2X",
"value" : "49.96666666666667"
}
},
"LedgerEntryType" : "Offer",
"LedgerIndex" : "C60F8CC514208FA5F7BD03CF1B64B38B7183CD52318FCBBD3726350D4FE693B0",
"PreviousFields" : {
"TakerGets" : "150000000000",
"TakerPays" : {
"currency" : "USD",
"issuer" : "r9vbV3EHvXWjSkeQ6CAcYVPGeq7TuiXY2X",
"value" : "50"
}
},
"PreviousTxnID" : "1A6AAE3F1AC5A8A7554A5ABC395D17FED5BF62CD90181AA8E4315EDFED4EDEB3",
"PreviousTxnLgrSeq" : 140734
}
*/
// 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(const SerializedTransaction& stTxn, TER terResult,TransactionMetaSet::pointer& meta,Json::Value& jvObj) void OrderBookDB::processTxn(const SerializedTransaction& stTxn, TER terResult,TransactionMetaSet::pointer& meta,Json::Value& jvObj)
{ {
// check if this is an offer or an offer cancel or a payment that consumes an offer if(terResult==tesSUCCESS)
//check to see what the meta looks like
BOOST_FOREACH(STObject& node,meta->getNodes())
{ {
if(node.getFieldU16(sfLedgerEntryType)==ltOFFER) // 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
BOOST_FOREACH(STObject& node,meta->getNodes())
{ {
try{
if(node.getFieldU16(sfLedgerEntryType)==ltOFFER)
{
SField* field=NULL;
if(node.getFName() == sfModifiedNode)
{
field=&sfPreviousFields;
}else if(node.getFName() == sfCreatedNode)
{
field=&sfNewFields;
}
const STObject* previous = dynamic_cast<const STObject*>(node.peekAtPField(*field));
if(previous)
{
STAmount& takerGets = previous->getFieldAmount(sfTakerGets);
uint160 currencyOut=takerGets.getCurrency();
uint160 issuerOut=takerGets.getIssuer();
STAmount& takerPays = previous->getFieldAmount(sfTakerPays);
uint160 currencyIn=takerPays.getCurrency();
uint160 issuerIn=takerPays.getIssuer();
// determine the OrderBook
BookListeners::pointer book=getBookListeners(currencyIn,currencyOut,issuerIn,issuerOut);
if(book) book->publish(jvObj);
}
}
}catch(...)
{
cLog(lsINFO) << "Fields not found in OrderBookDB::processTxn";
}
} }
} }
}
void BookListeners::addSubscriber(InfoSub* sub)
{
mListeners.insert(sub);
}
void BookListeners::removeSubscriber(InfoSub* sub)
{
mListeners.erase(sub);
}
void BookListeners::publish(Json::Value& jvObj)
{
//Json::Value jvObj=node.getJson(0);
BOOST_FOREACH(InfoSub* sub,mListeners)
{
sub->send(jvObj);
}
} }

View File

@@ -1,11 +1,24 @@
#include "Ledger.h" #include "Ledger.h"
#include "OrderBook.h" #include "OrderBook.h"
#include <boost/shared_ptr.hpp>
/* /*
we can eventually make this cached and just update it as transactions come in. we can eventually make this cached and just update it as transactions come in.
But for now it is probably faster to just generate it each time But for now it is probably faster to just generate it each time
*/ */
class BookListeners
{
boost::unordered_set<InfoSub*> mListeners;
public:
typedef boost::shared_ptr<BookListeners> pointer;
void addSubscriber(InfoSub* sub);
void removeSubscriber(InfoSub* sub);
void publish(Json::Value& jvObj);
};
class OrderBookDB class OrderBookDB
{ {
std::vector<OrderBook::pointer> mEmptyVector; std::vector<OrderBook::pointer> mEmptyVector;
@@ -13,6 +26,9 @@ class OrderBookDB
std::map<uint160, std::vector<OrderBook::pointer> > mIssuerMap; std::map<uint160, std::vector<OrderBook::pointer> > mIssuerMap;
//std::vector<OrderBook::pointer> mAllOrderBooks; //std::vector<OrderBook::pointer> mAllOrderBooks;
// issuerIn, issuerOut, currencyIn, currencyOut
std::map<uint160, std::map<uint160, std::map<uint160, std::map<uint160, BookListeners::pointer> > > > mListeners;
std::map<uint256, bool > mKnownMap; std::map<uint256, bool > mKnownMap;
public: public:
@@ -30,10 +46,11 @@ public:
float getPrice(uint160& currencyIn,uint160& currencyOut); float getPrice(uint160& currencyIn,uint160& currencyOut);
OrderBook::pointer getBook(uint160 mCurrencyIn, uint160 mCurrencyOut, uint160 mIssuerIn, uint160 mIssuerOut); BookListeners::pointer getBookListeners(uint160 currencyIn, uint160 currencyOut, uint160 issuerIn, uint160 issuerOut);
BookListeners::pointer makeBookListeners(uint160 currencyIn, uint160 currencyOut, uint160 issuerIn, uint160 issuerOut);
// see if this txn effects any orderbook // see if this txn effects any orderbook
void processTxn(const SerializedTransaction& stTxn, TER terResult,TransactionMetaSet::pointer& meta,Json::Value& jvObj); void processTxn(const SerializedTransaction& stTxn, TER terResult,TransactionMetaSet::pointer& meta,Json::Value& jvObj);
}; };
// vim:ts=4 // vim:ts=4

View File

@@ -12,8 +12,6 @@
SETUP_LOG(); SETUP_LOG();
/* /*
JED: V IIII
we just need to find a succession of the highest quality paths there until we find enough width we just need to find a succession of the highest quality paths there until we find enough width
Don't do branching within each path Don't do branching within each path
@@ -133,11 +131,13 @@ bool Pathfinder::bDefaultPath(const STPath& spPath)
// functionality is left to the future. // functionality is left to the future.
// //
Pathfinder::Pathfinder(const RippleAddress& uSrcAccountID, const RippleAddress& uDstAccountID, const uint160& uSrcCurrencyID, const uint160& uSrcIssuerID, const STAmount& saDstAmount) Pathfinder::Pathfinder(const RippleAddress& uSrcAccountID, const RippleAddress& uDstAccountID, const uint160& uSrcCurrencyID, const uint160& uSrcIssuerID, const STAmount& saDstAmount)
: mSrcAccountID(uSrcAccountID.getAccountID()), mDstAccountID(uDstAccountID.getAccountID()), mDstAmount(saDstAmount), mSrcCurrencyID(uSrcCurrencyID), mSrcIssuerID(uSrcIssuerID), mOrderBook(theApp->getLedgerMaster().getCurrentLedger()) : mSrcAccountID(uSrcAccountID.getAccountID()), mDstAccountID(uDstAccountID.getAccountID()), mDstAmount(saDstAmount), mSrcCurrencyID(uSrcCurrencyID), mSrcIssuerID(uSrcIssuerID)
{ {
mLedger = theApp->getLedgerMaster().getCurrentLedger(); mLedger = theApp->getLedgerMaster().getCurrentLedger();
mSrcAmount = STAmount(uSrcCurrencyID, uSrcIssuerID, 1, 0, true); // -1/uSrcIssuerID/uSrcIssuerID mSrcAmount = STAmount(uSrcCurrencyID, uSrcIssuerID, 1, 0, true); // -1/uSrcIssuerID/uSrcIssuerID
theApp->getOrderBookDB().setup( theApp->getLedgerMaster().getCurrentLedger()); // TODO: have the orderbook update itself rather than rebuild it from scratch each time
// Construct the default path for later comparison. // Construct the default path for later comparison.
PathState::pointer psDefault = boost::make_shared<PathState>(mDstAmount, mSrcAmount, mLedger); PathState::pointer psDefault = boost::make_shared<PathState>(mDstAmount, mSrcAmount, mLedger);

View File

@@ -2449,6 +2449,25 @@ Json::Value RPCHandler::doSubscribe(Json::Value jvRequest)
} }
} }
if (jvRequest.isMember("books"))
{
for (Json::Value::iterator it = jvRequest["books"].begin(); it != jvRequest["books"].end(); it++)
{
uint160 currencyOut;
STAmount::issuerFromString(currencyOut,(*it)["CurrencyOut"].asString());
uint160 issuerOut=RippleAddress::createNodePublic( (*it)["IssuerOut"].asString() ).getAccountID();
uint160 currencyIn;
STAmount::issuerFromString(currencyOut,(*it)["CurrencyIn"].asString());
uint160 issuerIn=RippleAddress::createNodePublic( (*it)["IssuerIn"].asString() ).getAccountID();
mNetOps->subBook(ispSub,currencyIn,currencyOut,issuerIn,issuerOut);
if((*it)["StateNow"].asBool())
{
}
}
}
return jvResult; return jvResult;
} }
@@ -2546,6 +2565,21 @@ Json::Value RPCHandler::doUnsubscribe(Json::Value jvRequest)
} }
} }
if (jvRequest.isMember("books"))
{
for (Json::Value::iterator it = jvRequest["books"].begin(); it != jvRequest["books"].end(); it++)
{
uint160 currencyOut;
STAmount::issuerFromString(currencyOut,(*it)["CurrencyOut"].asString());
uint160 issuerOut=RippleAddress::createNodePublic( (*it)["IssuerOut"].asString() ).getAccountID();
uint160 currencyIn;
STAmount::issuerFromString(currencyOut,(*it)["CurrencyIn"].asString());
uint160 issuerIn=RippleAddress::createNodePublic( (*it)["IssuerIn"].asString() ).getAccountID();
mNetOps->unsubBook(ispSub,currencyIn,currencyOut,issuerIn,issuerOut);
}
}
return jvResult; return jvResult;
} }

View File

@@ -40,8 +40,8 @@ buster.testCase("Fee Changes", {
*/ */
buster.testCase("Sending", { buster.testCase("Sending", {
'setUp' : testutils.build_setup(), //'setUp' : testutils.build_setup(),
// 'setUp' : testutils.build_setup({verbose: true , no_server: true}), 'setUp' : testutils.build_setup({verbose: true , no_server: true}),
'tearDown' : testutils.build_teardown(), 'tearDown' : testutils.build_teardown(),
"send XRP to non-existent account with insufficent fee" : "send XRP to non-existent account with insufficent fee" :
@@ -975,7 +975,7 @@ buster.testCase("Indirect ripple", {
}); });
}, },
"indirect ripple with path" : "=> indirect ripple with path" :
function (done) { function (done) {
var self = this; var self = this;