mirror of
https://github.com/XRPLF/rippled.git
synced 2025-11-20 11:05:54 +00:00
first draft
This commit is contained in:
@@ -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);
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -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
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user