More PFRequest work. Advanced features.

This commit is contained in:
JoelKatz
2013-05-02 01:04:16 -07:00
parent 6fb8e1515a
commit d193608aa1
5 changed files with 100 additions and 12 deletions

View File

@@ -4,6 +4,9 @@
#include "RPCErr.h"
#include "Ledger.h"
#include "Application.h"
#include "Pathfinder.h"
#include "RippleCalc.h"
#include "LedgerFormats.h"
boost::recursive_mutex PFRequest::sLock;
std::set<PFRequest::wptr> PFRequest::sRequests;
@@ -35,8 +38,10 @@ bool PFRequest::isValid(Ledger::ref lrLedger)
else
{
AccountState::pointer asDst = theApp->getOPs().getAccountState(lrLedger, raDstAccount);
Json::Value jvDestCur;
if (!asDst)
{ // no destination account
jvDestCur.append(Json::Value("XRP"));
if(!saDstAmount.isNative())
{ // only XRP can be send to a non-existent account
bValid = false;
@@ -48,21 +53,41 @@ bool PFRequest::isValid(Ledger::ref lrLedger)
jvStatus = rpcError(rpcDST_AMT_MALFORMED);
}
}
else
{
boost::unordered_set<uint160> usDestCurrID = usAccountDestCurrencies(raDstAccount, lrLedger, true);
BOOST_FOREACH(const uint160& uCurrency, usDestCurrID)
jvDestCur.append(STAmount::createHumanCurrency(uCurrency));
jvStatus["destination_tag"] = (asDst->peekSLE().getFlags() & lsfRequireDestTag) != 0;
}
jvStatus["destination_currencies"] = jvDestCur;
}
}
jvStatus["ledger_hash"] = lrLedger->getHash().GetHex();
jvStatus["ledger_index"] = lrLedger->getLedgerSeq();
return bValid;
}
Json::Value PFRequest::doCreate(Ledger::ref lrLedger, const Json::Value& value)
{
assert(lrLedger->isClosed());
Json::Value status;
bool mValid;
{
boost::recursive_mutex::scoped_lock sl(mLock);
parseJson(value, true);
status = jvStatus;
mValid = isValid(lrLedger);
if (parseJson(value, true) != PFR_PJ_INVALID)
{
mValid = isValid(lrLedger);
if (mValid)
{
RLCache::pointer cache = boost::make_shared<RLCache>(lrLedger);
doUpdate(cache, true);
}
}
else
mValid = false;
}
if (mValid)
@@ -167,4 +192,60 @@ Json::Value PFRequest::doStatus(const Json::Value&)
return jvStatus;
}
bool PFRequest::doUpdate(RLCache::ref cache, bool fast)
{
boost::recursive_mutex::scoped_lock sl(mLock);
jvStatus = Json::objectValue;
if (!isValid(cache->getLedger()))
return false;
std::set<currIssuer_t> sourceCurrencies(sciSourceCurrencies);
if (sourceCurrencies.empty())
{
boost::unordered_set<uint160> usCurrencies =
usAccountSourceCurrencies(raSrcAccount, cache->getLedger(), true);
bool sameAccount = raSrcAccount == raDstAccount;
BOOST_FOREACH(const uint160& c, usCurrencies)
{
if (!sameAccount || (c != saDstAmount.getCurrency()))
sourceCurrencies.insert(std::make_pair(c, ACCOUNT_XRP));
}
}
jvStatus["source_account"] = raSrcAccount.humanAccountID();
jvStatus["destination_account"] = raDstAccount.humanAccountID();
Json::Value jvArray = Json::arrayValue;
BOOST_FOREACH(const currIssuer_t& currIssuer, sourceCurrencies)
{
bool valid;
STPathSet spsPaths;
Pathfinder pf(cache, raSrcAccount, raDstAccount,
currIssuer.first, currIssuer.second, saDstAmount, valid);
if (valid && pf.findPaths(theConfig.PATH_SEARCH_SIZE - (fast ? 0 : 1), 3, spsPaths))
{
LedgerEntrySet lesSandbox(cache->getLedger(), tapNONE);
std::vector<PathState::pointer> vpsExpanded;
STAmount saMaxAmountAct;
STAmount saDstAmountAct;
STAmount saMaxAmount(currIssuer.first,
currIssuer.second.isNonZero() ? currIssuer.second :
(currIssuer.first.isZero() ? ACCOUNT_XRP : raSrcAccount.getAccountID()), 1);
TER terResult = RippleCalc::rippleCalc(lesSandbox, saMaxAmountAct, saDstAmountAct,
vpsExpanded, saMaxAmount, saDstAmount, raDstAccount.getAccountID(), raSrcAccount.getAccountID(),
spsPaths, false, false, false, true);
if (terResult == tesSUCCESS)
{
Json::Value jvEntry(Json::objectValue);
jvEntry["source_amount"] = saMaxAmountAct.getJson(0);
jvEntry["paths_computed"] = spsPaths.getJson(0);
jvArray.append(jvEntry);
}
}
}
jvStatus["alternatives"] = jvArray;
return true;
}
// vim:ts=4

View File

@@ -14,6 +14,7 @@
#include "uint256.h"
#include "RippleAddress.h"
#include "SerializedTypes.h"
#include "Pathfinder.h"
// A pathfinding request submitted by a client
// The request issuer must maintain a strong pointer
@@ -21,6 +22,7 @@
class Ledger;
class InfoSub;
class STAmount;
class RLCache;
// Return values from parseJson <0 = invalid, >0 = valid
#define PFR_PJ_INVALID -1
@@ -69,8 +71,7 @@ public:
Json::Value doClose(const Json::Value&);
Json::Value doStatus(const Json::Value&);
void doUpdate(); // do an update
void trigger(); // schedule an update
bool doUpdate(const boost::shared_ptr<RLCache>&, bool fast); // update jvStatus
static void updateAll(const boost::shared_ptr<Ledger> &);
};

View File

@@ -138,7 +138,7 @@ static int getEffectiveLength(const STPath& spPath)
return length;
}
Pathfinder::Pathfinder(Ledger::ref ledger, RLCache::ref cache,
Pathfinder::Pathfinder(RLCache::ref cache,
const RippleAddress& uSrcAccountID, const RippleAddress& uDstAccountID,
const uint160& uSrcCurrencyID, const uint160& uSrcIssuerID, const STAmount& saDstAmount, bool& bValid)
: mSrcAccountID(uSrcAccountID.getAccountID()),
@@ -147,7 +147,7 @@ Pathfinder::Pathfinder(Ledger::ref ledger, RLCache::ref cache,
mSrcCurrencyID(uSrcCurrencyID),
mSrcIssuerID(uSrcIssuerID),
mSrcAmount(uSrcCurrencyID, uSrcIssuerID, 1u, 0, true),
mLedger(ledger), mRLCache(cache)
mLedger(cache->getLedger()), mRLCache(cache)
{
if (((mSrcAccountID == mDstAccountID) && (mSrcCurrencyID == mDstAmount.getCurrency())) || mDstAmount.isZero())

View File

@@ -47,7 +47,9 @@ public:
typedef const pointer& ref;
RLCache(Ledger::ref l) : mLedger(l) { ; }
AccountItems& getRippleLines(const uint160& accountID);
Ledger::ref getLedger() { return mLedger; }
AccountItems& getRippleLines(const uint160& accountID);
};
class Pathfinder
@@ -83,7 +85,7 @@ class Pathfinder
bool isAuthRequired, bool isDestCurrency, const uint160& dest);
public:
Pathfinder(Ledger::ref ledger, RLCache::ref cache,
Pathfinder(RLCache::ref cache,
const RippleAddress& srcAccountID, const RippleAddress& dstAccountID,
const uint160& srcCurrencyID, const uint160& srcIssuerID, const STAmount& dstAmount, bool& bValid);

View File

@@ -182,7 +182,7 @@ Json::Value RPCHandler::transactionSign(Json::Value jvRequest, bool bSubmit)
ScopedUnlock su(theApp->getMasterLock());
bool bValid;
RLCache::pointer cache = boost::make_shared<RLCache>(lSnapshot);
Pathfinder pf(lSnapshot, cache, raSrcAddressID, dstAccountID,
Pathfinder pf(cache, raSrcAddressID, dstAccountID,
saSendMax.getCurrency(), saSendMax.getIssuer(), saSend, bValid);
if (!bValid || !pf.findPaths(theConfig.PATH_SEARCH_SIZE, 3, spsPaths))
@@ -1173,13 +1173,17 @@ Json::Value RPCHandler::doPathFind(Json::Value jvRequest, int& cost, ScopedLock&
{
if (!jvRequest.isMember("subcommand") || !jvRequest["subcommand"].isString())
return rpcError(rpcINVALID_PARAMS);
if (!mInfoSub)
return rpcError(rpcNO_EVENTS);
std::string sSubCommand = jvRequest["subcommand"].asString();
if (sSubCommand == "create")
{
mInfoSub->clearPFRequest();
PFRequest::pointer request = boost::make_shared<PFRequest>(mInfoSub);
Json::Value result = request->doCreate(mNetOps->getCurrentLedger(), jvRequest);
Json::Value result = request->doCreate(mNetOps->getClosedLedger(), jvRequest);
if (request->isValid())
mInfoSub->setPFRequest(request);
return result;
@@ -1342,7 +1346,7 @@ Json::Value RPCHandler::doRipplePathFind(Json::Value jvRequest, int& cost, Scope
STPathSet spsComputed;
bool bValid;
Pathfinder pf(lSnapShot, cache, raSrc, raDst, uSrcCurrencyID, uSrcIssuerID, saDstAmount, bValid);
Pathfinder pf(cache, raSrc, raDst, uSrcCurrencyID, uSrcIssuerID, saDstAmount, bValid);
if (!bValid || !pf.findPaths(theConfig.PATH_SEARCH_SIZE, 3, spsComputed))
{