mirror of
https://github.com/XRPLF/rippled.git
synced 2025-11-25 13:35:54 +00:00
Work on path finder integration.
This commit is contained in:
@@ -75,6 +75,14 @@ PathOption::PathOption(PathOption::pointer other)
|
||||
}
|
||||
#endif
|
||||
|
||||
// Return true, if path is a default path with an element.
|
||||
// XXX Could be determined via STAmount
|
||||
bool Pathfinder::bDefaultPath(const STPath& spPath)
|
||||
{
|
||||
return false;
|
||||
// return spPath.size() == 3 && spPath.mPath[1].mType;
|
||||
}
|
||||
|
||||
//
|
||||
// XXX Optionally, specifying a source and destination issuer might be nice. Especially, to convert between issuers. However, this
|
||||
// functionality is left to the future.
|
||||
@@ -88,11 +96,24 @@ Pathfinder::Pathfinder(const RippleAddress& srcAccountID, const RippleAddress& d
|
||||
// If possible, returns a single path.
|
||||
// --> maxSearchSteps: unused XXX
|
||||
// --> maxPay: unused XXX
|
||||
// <-- retPathSet: founds paths not including default paths.
|
||||
// Returns true if found paths.
|
||||
//
|
||||
// When generating a path set blindly, don't allow the empty path, it is implied by default.
|
||||
// When generating a path set for estimates, allow an empty path instead of no paths to indicate a path exists. The caller will
|
||||
// need to strip the empty path when submitting the transaction.
|
||||
bool Pathfinder::findPaths(int maxSearchSteps, int maxPay, STPathSet& retPathSet, bool bAllowEmpty)
|
||||
bool Pathfinder::findPaths(int maxSearchSteps, int maxPay, STPathSet& retPathSet)
|
||||
{
|
||||
bool bFound = false;
|
||||
|
||||
cLog(lsDEBUG) << boost::str(boost::format("findPaths> mSrcAccountID=%s mDstAccountID=%s mDstAmount=%s mSrcCurrencyID=%s mSrcIssuerID=%s")
|
||||
% RippleAddress::createHumanAccountID(mSrcAccountID)
|
||||
% RippleAddress::createHumanAccountID(mDstAccountID)
|
||||
% mDstAmount.getFullText()
|
||||
% STAmount::createHumanCurrency(mSrcCurrencyID)
|
||||
% RippleAddress::createHumanAccountID(mSrcIssuerID)
|
||||
);
|
||||
|
||||
if (mLedger) {
|
||||
std::queue<STPath> pqueue;
|
||||
STPathElement ele(mSrcAccountID,
|
||||
@@ -112,30 +133,45 @@ bool Pathfinder::findPaths(int maxSearchSteps, int maxPay, STPathSet& retPathSet
|
||||
ele = path.mPath.back(); // Get the last node from the path.
|
||||
|
||||
// Done, if dest wants XRP and last element produces XRP.
|
||||
if (!ele.mCurrencyID // Tail output is XRP
|
||||
&& !mDstAmount.getCurrency()) {
|
||||
if (!ele.mCurrencyID // Tail output is XRP.
|
||||
&& !mDstAmount.getCurrency()) { // Which is dst currency.
|
||||
|
||||
// Remove implied first.
|
||||
path.mPath.erase(path.mPath.begin());
|
||||
|
||||
// Return the path.
|
||||
retPathSet.addPath(path);
|
||||
if (path.size())
|
||||
{
|
||||
// There is an actual path element.
|
||||
|
||||
cLog(lsDEBUG) << "findPaths: adding: " << path.getJson(0);
|
||||
retPathSet.addPath(path); // Return the path.
|
||||
|
||||
cLog(lsDEBUG) << "findPaths: adding: " << path.getJson(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
cLog(lsDEBUG) << "findPaths: empty path: XRP->XRP";
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Done, if dest wants non-XRP and last element is dest.
|
||||
// YYY Allows going through self. Is this wanted?
|
||||
if (ele.mAccountID == mDstAccountID // Tail is destination
|
||||
if (ele.mAccountID == mDstAccountID // Tail is destination account.
|
||||
&& ele.mCurrencyID == mDstAmount.getCurrency()) { // With correct output currency.
|
||||
// Found a path to the destination.
|
||||
|
||||
if (!bAllowEmpty && 2 == path.mPath.size()) {
|
||||
// Empty path is default. Drop it.
|
||||
cLog(lsDEBUG) << "findPaths: dropping empty path.";
|
||||
continue;
|
||||
if (2 == path.mPath.size()) {
|
||||
// Empty path is a default. Don't need to add it to return set.
|
||||
cLog(lsDEBUG) << "findPaths: empty path: direct";
|
||||
|
||||
return true;
|
||||
}
|
||||
else if (bDefaultPath(path)) {
|
||||
// Path is a default (implied). Don't need to add it to return set.
|
||||
cLog(lsDEBUG) << "findPaths: default path: indirect: " << path.getJson(0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Remove implied first and last nodes.
|
||||
@@ -246,7 +282,7 @@ bool Pathfinder::findPaths(int maxSearchSteps, int maxPay, STPathSet& retPathSet
|
||||
cLog(lsWARNING) << boost::str(boost::format("findPaths: no ledger"));
|
||||
}
|
||||
|
||||
return false;
|
||||
return bFound;
|
||||
}
|
||||
|
||||
#if 0
|
||||
|
||||
@@ -52,7 +52,8 @@ class Pathfinder
|
||||
public:
|
||||
Pathfinder(const RippleAddress& srcAccountID, const RippleAddress& dstAccountID, const uint160& srcCurrencyID, const uint160& srcIssuerID, const STAmount& dstAmount);
|
||||
|
||||
// returns false if there is no path. otherwise fills out retPath
|
||||
bool findPaths(int maxSearchSteps, int maxPay, STPathSet& retPathSet, bool bAllowEmpty);
|
||||
bool findPaths(int maxSearchSteps, int maxPay, STPathSet& retPathSet);
|
||||
|
||||
bool bDefaultPath(const STPath& spPath);
|
||||
};
|
||||
// vim:ts=4
|
||||
|
||||
@@ -54,6 +54,7 @@ Json::Value RPCHandler::rpcError(int iError)
|
||||
{ rpcNO_EVENTS, "noEvents", "Current transport does not support events." },
|
||||
{ rpcNO_GEN_DECRPYT, "noGenDectypt", "Password failed to decrypt master public generator." },
|
||||
{ rpcNO_NETWORK, "noNetwork", "Network not available." },
|
||||
{ rpcNO_PATH, "noPath", "Unable to find a ripple path." },
|
||||
{ rpcNO_PERMISSION, "noPermission", "You don't have permission for this command." },
|
||||
{ rpcNOT_STANDALONE, "notStandAlone", "Operation valid in debug mode only." },
|
||||
{ rpcPASSWD_CHANGED, "passwdChanged", "Wrong key, password changed." },
|
||||
@@ -784,9 +785,7 @@ Json::Value RPCHandler::doRipplePathFind(const Json::Value& jvRequest)
|
||||
|
||||
Pathfinder pf(raSrc, raDst, uSrcCurrencyID, uSrcIssuerID, saDstAmount);
|
||||
|
||||
pf.findPaths(5, 1, spsComputed, true);
|
||||
|
||||
if (spsComputed.isEmpty())
|
||||
if (!pf.findPaths(5, 1, spsComputed))
|
||||
{
|
||||
cLog(lsDEBUG) << "ripple_path_find: No paths found.";
|
||||
}
|
||||
@@ -804,11 +803,7 @@ Json::Value RPCHandler::doRipplePathFind(const Json::Value& jvRequest)
|
||||
1);
|
||||
saMaxAmount.negate();
|
||||
|
||||
// Strip empty/default path.
|
||||
if (1 == spsComputed.size() && !spsComputed.begin()->size())
|
||||
{
|
||||
spsComputed.clear();
|
||||
}
|
||||
cLog(lsDEBUG) << "ripple_path_find: PATHS: " << spsComputed.size();
|
||||
|
||||
TER terResult =
|
||||
RippleCalc::rippleCalc(
|
||||
@@ -955,51 +950,54 @@ Json::Value RPCHandler::handleJSONSubmit(const Json::Value& jvRequest)
|
||||
txJSON["Fee"] = (int) theConfig.FEE_ACCOUNT_CREATE;
|
||||
}
|
||||
|
||||
if (!txJSON.isMember("Paths") && jvRequest.isMember("build_path"))
|
||||
if (!txJSON.isMember("Paths") && txJSON.isMember("Amount") && jvRequest.isMember("build_path"))
|
||||
{
|
||||
if (txJSON["Amount"].isObject() || txJSON.isMember("SendMax"))
|
||||
{ // we need a ripple path
|
||||
STPathSet spsPaths;
|
||||
uint160 uSrcCurrencyID;
|
||||
uint160 uSrcIssuerID;
|
||||
// Need a ripple path.
|
||||
STPathSet spsPaths;
|
||||
uint160 uSrcCurrencyID;
|
||||
uint160 uSrcIssuerID;
|
||||
|
||||
if (txJSON.isMember("SendMax") && txJSON["SendMax"].isMember("currency"))
|
||||
{
|
||||
STAmount::currencyFromString(uSrcCurrencyID, txJSON["SendMax"]["currency"].asString());
|
||||
}
|
||||
else
|
||||
{
|
||||
uSrcCurrencyID = CURRENCY_XRP;
|
||||
}
|
||||
STAmount saSendMax;
|
||||
STAmount saSend;
|
||||
|
||||
if (!!uSrcCurrencyID)
|
||||
{
|
||||
uSrcIssuerID = raSrcAddressID.getAccountID();
|
||||
}
|
||||
if (!txJSON.isMember("Amount") // Amount required.
|
||||
|| !saSend.bSetJson(txJSON["Amount"])) // Must be valid.
|
||||
return rpcError(rpcDST_AMT_MALFORMED);
|
||||
|
||||
STAmount dstAmount;
|
||||
if (txJSON.isMember("SendMax"))
|
||||
{
|
||||
if (!saSendMax.bSetJson(txJSON["SendMax"]))
|
||||
return rpcError(rpcINVALID_PARAMS);
|
||||
}
|
||||
else
|
||||
{
|
||||
// If no SendMax, default to Amount with sender as issuer.
|
||||
saSendMax = saSend;
|
||||
saSendMax.setIssuer(raSrcAddressID.getAccountID());
|
||||
}
|
||||
|
||||
if (!dstAmount.bSetJson(txJSON["Amount"]))
|
||||
{
|
||||
return rpcError(rpcDST_AMT_MALFORMED);
|
||||
}
|
||||
Pathfinder pf(raSrcAddressID, dstAccountID, saSendMax.getCurrency(), saSendMax.getIssuer(), saSend);
|
||||
|
||||
Pathfinder pf(raSrcAddressID, dstAccountID, uSrcCurrencyID, uSrcIssuerID, dstAmount);
|
||||
if (!pf.findPaths(5, 1, spsPaths))
|
||||
{
|
||||
cLog(lsDEBUG) << "payment: build_path: No paths found.";
|
||||
|
||||
pf.findPaths(5, 1, spsPaths, false);
|
||||
return rpcError(rpcNO_PATH);
|
||||
}
|
||||
else
|
||||
{
|
||||
cLog(lsDEBUG) << "payment: build_path: " << spsPaths.getJson(0);
|
||||
}
|
||||
|
||||
if (!spsPaths.isEmpty())
|
||||
{
|
||||
txJSON["Paths"]=spsPaths.getJson(0);
|
||||
if(txJSON.isMember("Flags")) txJSON["Flags"]=txJSON["Flags"].asUInt() | 2;
|
||||
else txJSON["Flags"]=2;
|
||||
}
|
||||
if (!spsPaths.isEmpty())
|
||||
{
|
||||
txJSON["Paths"]=spsPaths.getJson(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!txJSON.isMember("Sequence")) txJSON["Sequence"]=asSrc->getSeq();
|
||||
if(!txJSON.isMember("Flags")) txJSON["Flags"]=0;
|
||||
if (!txJSON.isMember("Sequence")) txJSON["Sequence"]=asSrc->getSeq();
|
||||
if (!txJSON.isMember("Flags")) txJSON["Flags"]=0;
|
||||
|
||||
Ledger::pointer lpCurrent = mNetOps->getCurrentLedger();
|
||||
SLE::pointer sleAccountRoot = mNetOps->getSLE(lpCurrent, Ledger::getAccountRootIndex(raSrcAddressID.getAccountID()));
|
||||
|
||||
@@ -121,6 +121,7 @@ public:
|
||||
rpcLGR_NOT_FOUND,
|
||||
rpcNICKNAME_MISSING,
|
||||
rpcNO_ACCOUNT,
|
||||
rpcNO_PATH,
|
||||
rpcPASSWD_CHANGED,
|
||||
rpcSRC_MISSING,
|
||||
rpcSRC_UNCLAIMED,
|
||||
|
||||
@@ -2328,9 +2328,10 @@ TER RippleCalc::rippleCalc(
|
||||
|
||||
// Incrementally search paths.
|
||||
|
||||
// bNoRippleDirect is a slight misnomer, it really means make no ripple default path.
|
||||
if (!bNoRippleDirect)
|
||||
{
|
||||
// Direct path.
|
||||
// Build a default path. Use saDstAmountReq and saMaxAmountReq to imply nodes.
|
||||
// XXX Might also make a XRP bridge by default.
|
||||
|
||||
PathState::pointer pspDirect = boost::make_shared<PathState>(saDstAmountReq, saMaxAmountReq, lesActive.getLedgerRef());
|
||||
|
||||
Reference in New Issue
Block a user