mirror of
https://github.com/XRPLF/rippled.git
synced 2025-12-06 17:27:55 +00:00
Add ripple quality in and out.
This commit is contained in:
@@ -64,8 +64,10 @@ LedgerEntryFormat LedgerFormats[]=
|
|||||||
{ S_FIELD(LowLimit), STI_AMOUNT, SOE_REQUIRED, 0 },
|
{ S_FIELD(LowLimit), STI_AMOUNT, SOE_REQUIRED, 0 },
|
||||||
{ S_FIELD(HighID), STI_ACCOUNT, SOE_REQUIRED, 0 },
|
{ S_FIELD(HighID), STI_ACCOUNT, SOE_REQUIRED, 0 },
|
||||||
{ S_FIELD(HighLimit), STI_AMOUNT, SOE_REQUIRED, 0 },
|
{ S_FIELD(HighLimit), STI_AMOUNT, SOE_REQUIRED, 0 },
|
||||||
{ S_FIELD(QualityIn), STI_UINT32, SOE_IFFLAG, 1 },
|
{ S_FIELD(LowQualityIn), STI_UINT32, SOE_IFFLAG, 1 },
|
||||||
{ S_FIELD(QualityOut), STI_UINT32, SOE_IFFLAG, 2 },
|
{ S_FIELD(LowQualityOut), STI_UINT32, SOE_IFFLAG, 2 },
|
||||||
|
{ S_FIELD(HighQualityIn), STI_UINT32, SOE_IFFLAG, 4 },
|
||||||
|
{ S_FIELD(HighQualityOut), STI_UINT32, SOE_IFFLAG, 8 },
|
||||||
{ S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x01000000 },
|
{ S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x01000000 },
|
||||||
{ sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } }
|
{ sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } }
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1125,7 +1125,7 @@ Json::Value RPCServer::doPeers(const Json::Value& params)
|
|||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ripple_line_set <seed> <paying_account> <destination_account> <limit_amount> [<currency>] [<accept_rate>]
|
// ripple_line_set <seed> <paying_account> <destination_account> <limit_amount> [<currency>] [<quality_in>] [<quality_out>]
|
||||||
Json::Value RPCServer::doRippleLineSet(const Json::Value& params)
|
Json::Value RPCServer::doRippleLineSet(const Json::Value& params)
|
||||||
{
|
{
|
||||||
NewcoinAddress naSeed;
|
NewcoinAddress naSeed;
|
||||||
@@ -1133,7 +1133,11 @@ Json::Value RPCServer::doRippleLineSet(const Json::Value& params)
|
|||||||
NewcoinAddress naDstAccountID;
|
NewcoinAddress naDstAccountID;
|
||||||
STAmount saLimitAmount;
|
STAmount saLimitAmount;
|
||||||
uint256 uLedger = mNetOps->getCurrentLedger();
|
uint256 uLedger = mNetOps->getCurrentLedger();
|
||||||
uint32 uAcceptRate = params.size() >= 6 ? lexical_cast_s<uint32>(params[5u].asString()) : 0;
|
bool bLimitAmount = true;
|
||||||
|
bool bQualityIn = params.size() >= 6;
|
||||||
|
bool bQualityOut = params.size() >= 7;
|
||||||
|
uint32 uQualityIn = bQualityIn ? lexical_cast_s<uint32>(params[5u].asString()) : 0;
|
||||||
|
uint32 uQualityOut = bQualityOut ? lexical_cast_s<uint32>(params[6u].asString()) : 0;
|
||||||
|
|
||||||
if (!naSeed.setSeedGeneric(params[0u].asString()))
|
if (!naSeed.setSeedGeneric(params[0u].asString()))
|
||||||
{
|
{
|
||||||
@@ -1171,8 +1175,9 @@ Json::Value RPCServer::doRippleLineSet(const Json::Value& params)
|
|||||||
theConfig.FEE_DEFAULT,
|
theConfig.FEE_DEFAULT,
|
||||||
0, // YYY No source tag
|
0, // YYY No source tag
|
||||||
naDstAccountID,
|
naDstAccountID,
|
||||||
saLimitAmount,
|
bLimitAmount, saLimitAmount,
|
||||||
uAcceptRate);
|
bQualityIn, uQualityIn,
|
||||||
|
bQualityOut, uQualityOut);
|
||||||
|
|
||||||
trans = mNetOps->submitTransaction(trans);
|
trans = mNetOps->submitTransaction(trans);
|
||||||
|
|
||||||
@@ -1181,8 +1186,6 @@ Json::Value RPCServer::doRippleLineSet(const Json::Value& params)
|
|||||||
obj["seed"] = naSeed.humanSeed();
|
obj["seed"] = naSeed.humanSeed();
|
||||||
obj["srcAccountID"] = naSrcAccountID.humanAccountID();
|
obj["srcAccountID"] = naSrcAccountID.humanAccountID();
|
||||||
obj["dstAccountID"] = naDstAccountID.humanAccountID();
|
obj["dstAccountID"] = naDstAccountID.humanAccountID();
|
||||||
obj["limitAmount"] = saLimitAmount.getText();
|
|
||||||
obj["acceptRate"] = uAcceptRate;
|
|
||||||
|
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
@@ -2133,7 +2136,7 @@ Json::Value RPCServer::doCommand(const std::string& command, Json::Value& params
|
|||||||
{ "password_set", &RPCServer::doPasswordSet, 2, 3, false, optNetwork },
|
{ "password_set", &RPCServer::doPasswordSet, 2, 3, false, optNetwork },
|
||||||
{ "peers", &RPCServer::doPeers, 0, 0, true },
|
{ "peers", &RPCServer::doPeers, 0, 0, true },
|
||||||
{ "ripple_lines_get", &RPCServer::doRippleLinesGet, 1, 2, false, optCurrent|optClosed },
|
{ "ripple_lines_get", &RPCServer::doRippleLinesGet, 1, 2, false, optCurrent|optClosed },
|
||||||
{ "ripple_line_set", &RPCServer::doRippleLineSet, 4, 6, false, optCurrent },
|
{ "ripple_line_set", &RPCServer::doRippleLineSet, 4, 7, false, optCurrent },
|
||||||
{ "send", &RPCServer::doSend, 3, 7, false, optCurrent },
|
{ "send", &RPCServer::doSend, 3, 7, false, optCurrent },
|
||||||
{ "server_info", &RPCServer::doServerInfo, 0, 0, true },
|
{ "server_info", &RPCServer::doServerInfo, 0, 0, true },
|
||||||
{ "stop", &RPCServer::doStop, 0, 0, true },
|
{ "stop", &RPCServer::doStop, 0, 0, true },
|
||||||
|
|||||||
@@ -55,6 +55,8 @@ enum SOE_Field
|
|||||||
sfHash,
|
sfHash,
|
||||||
sfHighID,
|
sfHighID,
|
||||||
sfHighLimit,
|
sfHighLimit,
|
||||||
|
sfHighQualityIn,
|
||||||
|
sfHighQualityOut,
|
||||||
sfIdentifier,
|
sfIdentifier,
|
||||||
sfIndexes,
|
sfIndexes,
|
||||||
sfIndexNext,
|
sfIndexNext,
|
||||||
@@ -67,6 +69,8 @@ enum SOE_Field
|
|||||||
sfLimitAmount,
|
sfLimitAmount,
|
||||||
sfLowID,
|
sfLowID,
|
||||||
sfLowLimit,
|
sfLowLimit,
|
||||||
|
sfLowQualityIn,
|
||||||
|
sfLowQualityOut,
|
||||||
sfMessageKey,
|
sfMessageKey,
|
||||||
sfMinimumOffer,
|
sfMinimumOffer,
|
||||||
sfNextAcceptExpire,
|
sfNextAcceptExpire,
|
||||||
|
|||||||
@@ -36,6 +36,20 @@ enum SerializedTypeID
|
|||||||
STI_LEDGERENTRY = 102
|
STI_LEDGERENTRY = 102
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum PathFlags
|
||||||
|
{
|
||||||
|
PF_END = 0x00, // End of current path & path list.
|
||||||
|
PF_BOUNDRY = 0xFF, // End of current path & new path follows.
|
||||||
|
|
||||||
|
PF_ACCOUNT = 0x01,
|
||||||
|
PF_OFFER = 0x02,
|
||||||
|
|
||||||
|
PF_WANTED_CURRENCY = 0x10,
|
||||||
|
PF_WANTED_ISSUER = 0x20,
|
||||||
|
PF_REDEEM = 0x40,
|
||||||
|
PF_ISSUE = 0x80,
|
||||||
|
};
|
||||||
|
|
||||||
class SerializedType
|
class SerializedType
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
|
|||||||
@@ -232,13 +232,23 @@ Transaction::pointer Transaction::sharedCreate(
|
|||||||
Transaction::pointer Transaction::setCreditSet(
|
Transaction::pointer Transaction::setCreditSet(
|
||||||
const NewcoinAddress& naPrivateKey,
|
const NewcoinAddress& naPrivateKey,
|
||||||
const NewcoinAddress& naDstAccountID,
|
const NewcoinAddress& naDstAccountID,
|
||||||
|
bool bLimitAmount,
|
||||||
const STAmount& saLimitAmount,
|
const STAmount& saLimitAmount,
|
||||||
uint32 uAcceptRate)
|
bool bQualityIn,
|
||||||
|
uint32 uQualityIn,
|
||||||
|
bool bQualityOut,
|
||||||
|
uint32 uQualityOut)
|
||||||
{
|
{
|
||||||
mTransaction->setITFieldAccount(sfDestination, naDstAccountID);
|
mTransaction->setITFieldAccount(sfDestination, naDstAccountID);
|
||||||
|
|
||||||
|
if (bLimitAmount)
|
||||||
mTransaction->setITFieldAmount(sfLimitAmount, saLimitAmount);
|
mTransaction->setITFieldAmount(sfLimitAmount, saLimitAmount);
|
||||||
if (uAcceptRate)
|
|
||||||
mTransaction->setITFieldU32(sfAcceptRate, uAcceptRate);
|
if (bQualityIn)
|
||||||
|
mTransaction->setITFieldU32(sfAcceptRate, uQualityIn);
|
||||||
|
|
||||||
|
if (bQualityOut)
|
||||||
|
mTransaction->setITFieldU32(sfAcceptRate, uQualityOut);
|
||||||
|
|
||||||
sign(naPrivateKey);
|
sign(naPrivateKey);
|
||||||
|
|
||||||
@@ -252,12 +262,19 @@ Transaction::pointer Transaction::sharedCreditSet(
|
|||||||
const STAmount& saFee,
|
const STAmount& saFee,
|
||||||
uint32 uSourceTag,
|
uint32 uSourceTag,
|
||||||
const NewcoinAddress& naDstAccountID,
|
const NewcoinAddress& naDstAccountID,
|
||||||
|
bool bLimitAmount,
|
||||||
const STAmount& saLimitAmount,
|
const STAmount& saLimitAmount,
|
||||||
uint32 uAcceptRate)
|
bool bQualityIn,
|
||||||
|
uint32 uQualityIn,
|
||||||
|
bool bQualityOut,
|
||||||
|
uint32 uQualityOut)
|
||||||
{
|
{
|
||||||
pointer tResult = boost::make_shared<Transaction>(ttCREDIT_SET, naPublicKey, naSourceAccount, uSeq, saFee, uSourceTag);
|
pointer tResult = boost::make_shared<Transaction>(ttCREDIT_SET, naPublicKey, naSourceAccount, uSeq, saFee, uSourceTag);
|
||||||
|
|
||||||
return tResult->setCreditSet(naPrivateKey, naDstAccountID, saLimitAmount, uAcceptRate);
|
return tResult->setCreditSet(naPrivateKey, naDstAccountID,
|
||||||
|
bLimitAmount, saLimitAmount,
|
||||||
|
bQualityIn, uQualityIn,
|
||||||
|
bQualityOut, uQualityOut);
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -68,8 +68,12 @@ private:
|
|||||||
Transaction::pointer setCreditSet(
|
Transaction::pointer setCreditSet(
|
||||||
const NewcoinAddress& naPrivateKey,
|
const NewcoinAddress& naPrivateKey,
|
||||||
const NewcoinAddress& naDstAccountID,
|
const NewcoinAddress& naDstAccountID,
|
||||||
|
bool bLimitAmount,
|
||||||
const STAmount& saLimitAmount,
|
const STAmount& saLimitAmount,
|
||||||
uint32 uAcceptRate);
|
bool bQualityIn,
|
||||||
|
uint32 uQualityIn,
|
||||||
|
bool bQualityOut,
|
||||||
|
uint32 uQualityOut);
|
||||||
|
|
||||||
Transaction::pointer setNicknameSet(
|
Transaction::pointer setNicknameSet(
|
||||||
const NewcoinAddress& naPrivateKey,
|
const NewcoinAddress& naPrivateKey,
|
||||||
@@ -166,8 +170,12 @@ public:
|
|||||||
const STAmount& saFee,
|
const STAmount& saFee,
|
||||||
uint32 uSourceTag,
|
uint32 uSourceTag,
|
||||||
const NewcoinAddress& naDstAccountID,
|
const NewcoinAddress& naDstAccountID,
|
||||||
|
bool bLimitAmount,
|
||||||
const STAmount& saLimitAmount,
|
const STAmount& saLimitAmount,
|
||||||
uint32 uAcceptRate);
|
bool bQualityIn,
|
||||||
|
uint32 uQualityIn,
|
||||||
|
bool bQualityOut,
|
||||||
|
uint32 uQualityOut);
|
||||||
|
|
||||||
// Set Nickname
|
// Set Nickname
|
||||||
static Transaction::pointer sharedNicknameSet(
|
static Transaction::pointer sharedNicknameSet(
|
||||||
|
|||||||
@@ -111,6 +111,7 @@ STAmount TransactionEngine::rippleHolds(const uint160& uAccountID, const uint160
|
|||||||
return saBalance;
|
return saBalance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// <-- saAmount: amount of uCurrency held by uAccountID. May be negative.
|
||||||
STAmount TransactionEngine::accountHolds(const uint160& uAccountID, const uint160& uCurrency, const uint160& uIssuerID)
|
STAmount TransactionEngine::accountHolds(const uint160& uAccountID, const uint160& uCurrency, const uint160& uIssuerID)
|
||||||
{
|
{
|
||||||
STAmount saAmount;
|
STAmount saAmount;
|
||||||
@@ -138,7 +139,11 @@ STAmount TransactionEngine::accountHolds(const uint160& uAccountID, const uint16
|
|||||||
return saAmount;
|
return saAmount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Returns the funds available for uAccountID for a currency/issuer.
|
||||||
|
// Use when you need a default for rippling uAccountID's currency.
|
||||||
// --> saDefault/currency/issuer
|
// --> saDefault/currency/issuer
|
||||||
|
// <-- saFunds: Funds available. May be negative.
|
||||||
|
// If the issuer is the same as uAccountID, result is Default.
|
||||||
STAmount TransactionEngine::accountFunds(const uint160& uAccountID, const STAmount& saDefault)
|
STAmount TransactionEngine::accountFunds(const uint160& uAccountID, const STAmount& saDefault)
|
||||||
{
|
{
|
||||||
STAmount saFunds;
|
STAmount saFunds;
|
||||||
@@ -582,30 +587,55 @@ TransactionEngineResult TransactionEngine::dirDelete(
|
|||||||
return terSUCCESS;
|
return terSUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
// --> uRootIndex
|
// <-- true, if had a next entry.
|
||||||
// <-- uEntryIndex
|
bool TransactionEngine::dirFirst(
|
||||||
// <-- uEntryNode
|
const uint256& uRootIndex, // --> Root of directory.
|
||||||
void TransactionEngine::dirFirst(const uint256& uRootIndex, uint256& uEntryIndex, uint64& uEntryNode)
|
SLE::pointer& sleNode, // <-> current node
|
||||||
|
unsigned int& uDirEntry, // <-- next entry
|
||||||
|
uint256& uEntryIndex) // <-- The entry, if available. Otherwise, zero.
|
||||||
{
|
{
|
||||||
SLE::pointer sleRoot = entryCache(ltDIR_NODE, uRootIndex);
|
sleNode = entryCache(ltDIR_NODE, uRootIndex);
|
||||||
|
uDirEntry = 0;
|
||||||
|
|
||||||
STVector256 svIndexes = sleRoot->getIFieldV256(sfIndexes);
|
assert(sleNode); // We never probe for directories.
|
||||||
|
|
||||||
|
return TransactionEngine::dirNext(uRootIndex, sleNode, uDirEntry, uEntryIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
// <-- true, if had a next entry.
|
||||||
|
bool TransactionEngine::dirNext(
|
||||||
|
const uint256& uRootIndex, // --> Root of directory
|
||||||
|
SLE::pointer& sleNode, // <-> current node
|
||||||
|
unsigned int& uDirEntry, // <-> next entry
|
||||||
|
uint256& uEntryIndex) // <-- The entry, if available. Otherwise, zero.
|
||||||
|
{
|
||||||
|
STVector256 svIndexes = sleNode->getIFieldV256(sfIndexes);
|
||||||
std::vector<uint256>& vuiIndexes = svIndexes.peekValue();
|
std::vector<uint256>& vuiIndexes = svIndexes.peekValue();
|
||||||
|
|
||||||
if (vuiIndexes.empty())
|
if (uDirEntry == vuiIndexes.size())
|
||||||
{
|
{
|
||||||
uEntryNode = sleRoot->getIFieldU64(sfIndexNext);
|
uint64 uNodeNext = sleNode->getIFieldU64(sfIndexNext);
|
||||||
|
|
||||||
SLE::pointer sleNext = entryCache(ltDIR_NODE, Ledger::getDirNodeIndex(uRootIndex, uEntryNode));
|
if (!uNodeNext)
|
||||||
uEntryIndex = sleNext->getIFieldV256(sfIndexes).peekValue()[0];
|
{
|
||||||
|
uEntryIndex.zero();
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
uEntryIndex = vuiIndexes[0];
|
sleNode = entryCache(ltDIR_NODE, Ledger::getDirNodeIndex(uRootIndex, uNodeNext));
|
||||||
uEntryNode = 0;
|
uDirEntry = 0;
|
||||||
|
|
||||||
|
return dirNext(uRootIndex, sleNode, uDirEntry, uEntryIndex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uEntryIndex = vuiIndexes[uDirEntry++];
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// Set the authorized public key for an account. May also set the generator map.
|
// Set the authorized public key for an account. May also set the generator map.
|
||||||
TransactionEngineResult TransactionEngine::setAuthorized(const SerializedTransaction& txn, bool bMustSetGenerator)
|
TransactionEngineResult TransactionEngine::setAuthorized(const SerializedTransaction& txn, bool bMustSetGenerator)
|
||||||
{
|
{
|
||||||
@@ -1329,10 +1359,15 @@ TransactionEngineResult TransactionEngine::doCreditSet(const SerializedTransacti
|
|||||||
return terNO_DST;
|
return terNO_DST;
|
||||||
}
|
}
|
||||||
|
|
||||||
STAmount saLimitAmount = txn.getITFieldAmount(sfLimitAmount);
|
|
||||||
uint160 uCurrency = saLimitAmount.getCurrency();
|
|
||||||
bool bFlipped = mTxnAccountID > uDstAccountID;
|
bool bFlipped = mTxnAccountID > uDstAccountID;
|
||||||
uint32 uFlags = bFlipped ? lsfLowIndexed : lsfHighIndexed;
|
uint32 uFlags = bFlipped ? lsfLowIndexed : lsfHighIndexed;
|
||||||
|
bool bLimitAmount = txn.getITFieldPresent(sfLimitAmount);
|
||||||
|
STAmount saLimitAmount = bLimitAmount ? txn.getITFieldAmount(sfLimitAmount) : STAmount();
|
||||||
|
bool bQualityIn = txn.getITFieldPresent(sfQualityIn);
|
||||||
|
uint32 uQualityIn = bQualityIn ? txn.getITFieldU32(sfQualityIn) : 0;
|
||||||
|
bool bQualityOut = txn.getITFieldPresent(sfQualityOut);
|
||||||
|
uint32 uQualityOut = bQualityIn ? txn.getITFieldU32(sfQualityOut) : 0;
|
||||||
|
uint160 uCurrency = saLimitAmount.getCurrency();
|
||||||
STAmount saBalance(uCurrency);
|
STAmount saBalance(uCurrency);
|
||||||
bool bAddIndex = false;
|
bool bAddIndex = false;
|
||||||
bool bDelIndex = false;
|
bool bDelIndex = false;
|
||||||
@@ -1364,12 +1399,40 @@ TransactionEngineResult TransactionEngine::doCreditSet(const SerializedTransacti
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (!bDelIndex)
|
if (!bDelIndex)
|
||||||
{
|
{
|
||||||
bAddIndex = !(sleRippleState->getFlags() & uFlags);
|
if (bLimitAmount)
|
||||||
|
|
||||||
sleRippleState->setIFieldAmount(bFlipped ? sfHighLimit: sfLowLimit , saLimitAmount);
|
sleRippleState->setIFieldAmount(bFlipped ? sfHighLimit: sfLowLimit , saLimitAmount);
|
||||||
|
|
||||||
|
if (!bQualityIn)
|
||||||
|
{
|
||||||
|
nothing();
|
||||||
|
}
|
||||||
|
else if (uQualityIn)
|
||||||
|
{
|
||||||
|
sleRippleState->setIFieldU32(bFlipped ? sfLowQualityIn : sfHighQualityIn, uQualityIn);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sleRippleState->makeIFieldAbsent(bFlipped ? sfLowQualityIn : sfHighQualityIn);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!bQualityOut)
|
||||||
|
{
|
||||||
|
nothing();
|
||||||
|
}
|
||||||
|
else if (uQualityOut)
|
||||||
|
{
|
||||||
|
sleRippleState->setIFieldU32(bFlipped ? sfLowQualityOut : sfHighQualityOut, uQualityOut);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sleRippleState->makeIFieldAbsent(bFlipped ? sfLowQualityOut : sfHighQualityOut);
|
||||||
|
}
|
||||||
|
|
||||||
|
bAddIndex = !(sleRippleState->getFlags() & uFlags);
|
||||||
|
|
||||||
if (bAddIndex)
|
if (bAddIndex)
|
||||||
sleRippleState->setFlag(uFlags);
|
sleRippleState->setFlag(uFlags);
|
||||||
|
|
||||||
@@ -1401,6 +1464,10 @@ TransactionEngineResult TransactionEngine::doCreditSet(const SerializedTransacti
|
|||||||
sleRippleState->setIFieldAmount(bFlipped ? sfLowLimit : sfHighLimit, saZero);
|
sleRippleState->setIFieldAmount(bFlipped ? sfLowLimit : sfHighLimit, saZero);
|
||||||
sleRippleState->setIFieldAccount(bFlipped ? sfHighID : sfLowID, mTxnAccountID);
|
sleRippleState->setIFieldAccount(bFlipped ? sfHighID : sfLowID, mTxnAccountID);
|
||||||
sleRippleState->setIFieldAccount(bFlipped ? sfLowID : sfHighID, uDstAccountID);
|
sleRippleState->setIFieldAccount(bFlipped ? sfLowID : sfHighID, uDstAccountID);
|
||||||
|
if (uQualityIn)
|
||||||
|
sleRippleState->setIFieldU32(bFlipped ? sfLowQualityIn : sfHighQualityIn, uQualityIn);
|
||||||
|
if (uQualityOut)
|
||||||
|
sleRippleState->setIFieldU32(bFlipped ? sfLowQualityOut : sfHighQualityOut, uQualityOut);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bAddIndex)
|
if (bAddIndex)
|
||||||
@@ -1517,19 +1584,9 @@ TransactionEngineResult TransactionEngine::doPasswordSet(const SerializedTransac
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef WORK_IN_PROGRESS
|
#ifdef WORK_IN_PROGRESS
|
||||||
TransactionEngineResult calcOfferFill(SAAmount& saSrc, paymentNode& pnSrc, paymentNode& pnDst)
|
// XXX Need to adjust for fees.
|
||||||
{
|
|
||||||
TransactionEngineResult terResult;
|
|
||||||
|
|
||||||
if (!saSrc.isZero())
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return bSuccess;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find offers to satisfy pnDst.
|
// Find offers to satisfy pnDst.
|
||||||
|
// - Does not adjust any balances as there is at least a forward pass to come.
|
||||||
// --> pnDst.saWanted: currency and amount wanted
|
// --> pnDst.saWanted: currency and amount wanted
|
||||||
// --> pnSrc.saIOURedeem.mCurrency: use this before saIOUIssue, limit to use.
|
// --> pnSrc.saIOURedeem.mCurrency: use this before saIOUIssue, limit to use.
|
||||||
// --> pnSrc.saIOUIssue.mCurrency: use this after saIOURedeem, limit to use.
|
// --> pnSrc.saIOUIssue.mCurrency: use this after saIOURedeem, limit to use.
|
||||||
@@ -1543,25 +1600,389 @@ TransactionEngineResult calcOfferFill(paymentNode& pnSrc, paymentNode& pnDst, bo
|
|||||||
{
|
{
|
||||||
TransactionEngineResult terResult;
|
TransactionEngineResult terResult;
|
||||||
|
|
||||||
terResult = calcOfferFill(pnSrc.saIOURedeem, pnSrc, pnDst, bAllowPartial);
|
if (pnDst.saWanted.isNative())
|
||||||
|
{
|
||||||
|
// Transfer stamps.
|
||||||
|
|
||||||
|
STAmount saSrcFunds = pnSrc.saAccount->accountHolds(pnSrc.saAccount, uint160(0), uint160(0));
|
||||||
|
|
||||||
|
if (saSrcFunds && (bAllowPartial || saSrcFunds > pnDst.saWanted))
|
||||||
|
{
|
||||||
|
pnSrc.saSend = min(saSrcFunds, pnDst.saWanted);
|
||||||
|
pnDst.saReceive = pnSrc.saSend;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
terResult = terINSUF_PATH;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Ripple funds.
|
||||||
|
{
|
||||||
|
prv->saSend = min(prv->account->saBalance(), cur->saWanted);
|
||||||
|
// Redeem to limit.
|
||||||
|
terResult = calcOfferFill(
|
||||||
|
accountHolds(pnSrc.saAccount, pnDst.saWanted.getCurrency(), pnDst.saWanted.getIssuer()),
|
||||||
|
pnSrc.saIOURedeem,
|
||||||
|
pnDst.saIOUForgive,
|
||||||
|
bAllowPartial);
|
||||||
|
|
||||||
if (terSUCCESS == terResult)
|
if (terSUCCESS == terResult)
|
||||||
{
|
{
|
||||||
terResult = calcOfferFill(pnSrc.saIOUIssue, pnSrc, pnDst, bAllowPartial)
|
// Issue to wanted.
|
||||||
|
terResult = calcOfferFill(
|
||||||
|
pnDst.saWanted, // As much as wanted is available, limited by credit limit.
|
||||||
|
pnSrc.saIOUIssue,
|
||||||
|
pnDst.saIOUAccept,
|
||||||
|
bAllowPartial);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (terSUCCESS == terResult && !bAllowPartial)
|
if (terSUCCESS == terResult && !bAllowPartial)
|
||||||
{
|
{
|
||||||
STAmount saTotal = pnSrc.saIOURedeem;
|
STAmount saTotal = pnDst.saIOUForgive + pnSrc.saIOUAccept;
|
||||||
saTotal += pnSrc.saIOUIssue;
|
|
||||||
|
|
||||||
if (saTotal != saWanted)
|
if (saTotal != saWanted)
|
||||||
terResult = terINSUF_PATH;
|
terResult = terINSUF_PATH;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return terResult;
|
return terResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get the next offer limited by funding.
|
||||||
|
// - Stop when becomes unfunded.
|
||||||
|
void TransactionEngine::calcOfferBridgeNext(
|
||||||
|
const uint256& uBookRoot, // --> Which order book to look in.
|
||||||
|
const uint256& uBookEnd, // --> Limit of how far to look.
|
||||||
|
uint256& uBookDirIndex, // <-> Current directory. <-- 0 = no offer available.
|
||||||
|
uint64& uBookDirNode, // <-> Which node. 0 = first.
|
||||||
|
unsigned int& uBookDirEntry, // <-> Entry in node. 0 = first.
|
||||||
|
STAmount& saOfferIn, // <-- How much to pay in, fee inclusive, to get saOfferOut out.
|
||||||
|
STAmount& saOfferOut // <-- How much offer pays out.
|
||||||
|
)
|
||||||
|
{
|
||||||
|
saOfferIn = 0; // XXX currency & issuer
|
||||||
|
saOfferOut = 0; // XXX currency & issuer
|
||||||
|
|
||||||
|
bool bDone = false;
|
||||||
|
|
||||||
|
while (!bDone)
|
||||||
|
{
|
||||||
|
uint256 uOfferIndex;
|
||||||
|
|
||||||
|
// Get uOfferIndex.
|
||||||
|
dirNext(uBookRoot, uBookEnd, uBookDirIndex, uBookDirNode, uBookDirEntry, uOfferIndex);
|
||||||
|
|
||||||
|
SLE::pointer sleOffer = entryCache(ltOFFER, uOfferIndex);
|
||||||
|
|
||||||
|
uint160 uOfferOwnerID = sleOffer->getIValueFieldAccount(sfAccount).getAccountID();
|
||||||
|
STAmount saOfferPays = sleOffer->getIValueFieldAmount(sfTakerGets);
|
||||||
|
STAmount saOfferGets = sleOffer->getIValueFieldAmount(sfTakerPays);
|
||||||
|
|
||||||
|
if (sleOffer->getIFieldPresent(sfGetsIssuer))
|
||||||
|
saOfferPays.setIssuer(sleOffer->getIValueFieldAccount(sfGetsIssuer).getAccountID());
|
||||||
|
|
||||||
|
if (sleOffer->getIFieldPresent(sfPaysIssuer))
|
||||||
|
saOfferGets.setIssuer(sleOffer->getIValueFieldAccount(sfPaysIssuer).getAccountID());
|
||||||
|
|
||||||
|
if (sleOffer->getIFieldPresent(sfExpiration) && sleOffer->getIFieldU32(sfExpiration) <= mLedger->getParentCloseTimeNC())
|
||||||
|
{
|
||||||
|
// Offer is expired.
|
||||||
|
Log(lsINFO) << "calcOfferFirst: encountered expired offer";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
STAmount saOfferFunds = accountFunds(uOfferOwnerID, saOfferPays);
|
||||||
|
// Outbound fees are paid by offer owner.
|
||||||
|
// XXX Calculate outbound fee rate.
|
||||||
|
|
||||||
|
if (saOfferPays.isNative())
|
||||||
|
{
|
||||||
|
// No additional fees for stamps.
|
||||||
|
|
||||||
|
nothing();
|
||||||
|
}
|
||||||
|
else if (saOfferPays.getIssuer() == uOfferOwnerID)
|
||||||
|
{
|
||||||
|
// Offerer is issue own IOUs.
|
||||||
|
// No fees at this exact point, XXX receiving node may charge a fee.
|
||||||
|
// XXX Make sure has a credit line with receiver, limit by credit line.
|
||||||
|
|
||||||
|
nothing();
|
||||||
|
// XXX Broken - could be issuing or redeeming or both.
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Offer must be redeeming IOUs.
|
||||||
|
|
||||||
|
// No additional
|
||||||
|
// XXX Broken
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!saOfferFunds.isPositive())
|
||||||
|
{
|
||||||
|
// Offer is unfunded.
|
||||||
|
Log(lsINFO) << "calcOfferFirst: offer unfunded: delete";
|
||||||
|
}
|
||||||
|
else if (saOfferFunds >= saOfferPays)
|
||||||
|
{
|
||||||
|
// Offer fully funded.
|
||||||
|
|
||||||
|
// Account transfering funds in to offer always pays inbound fees.
|
||||||
|
//
|
||||||
|
saOfferIn = saOfferGets; // XXX Add in fees?
|
||||||
|
|
||||||
|
saOfferOut = saOfferPays;
|
||||||
|
|
||||||
|
bDone = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Offer partially funded.
|
||||||
|
|
||||||
|
// saOfferIn/saOfferFunds = saOfferGets/saOfferPays
|
||||||
|
// XXX Round such that all saOffer funds are exhausted.
|
||||||
|
saOfferIn = (saOfferFunds*saOfferGets)/saOfferPays; // XXX Add in fees?
|
||||||
|
saOfferOut = saOfferFunds;
|
||||||
|
|
||||||
|
bDone = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!bDone)
|
||||||
|
{
|
||||||
|
// mUnfunded.insert(uOfferIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (bNext);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If either currency is not stamps, then also calculates vs stamp bridge.
|
||||||
|
// --> saWanted: Limit of how much is wanted out.
|
||||||
|
// <-- saPay: How much to pay into the offer.
|
||||||
|
// <-- saGot: How much to the offer pays out. Never more than saWanted.
|
||||||
|
void TransactionEngine::calcNodeOfferReverse(
|
||||||
|
const uint160& uPayCurrency,
|
||||||
|
const uint160& uPayIssuerID,
|
||||||
|
const STAmount& saWanted, // Driver
|
||||||
|
|
||||||
|
STAmount& saPay,
|
||||||
|
STAmount& saGot
|
||||||
|
) const
|
||||||
|
{
|
||||||
|
TransactionEngineResult terResult = tenUNKNOWN;
|
||||||
|
|
||||||
|
bool bDirectNext = true; // True, if need to load.
|
||||||
|
uint256 uDirectQuality;
|
||||||
|
uint256 uDirectTip = Ledger::getBookBase(uGetsCurrency, uGetsIssuerID, uPaysCurrency, uPaysIssuerID);
|
||||||
|
uint256 uDirectEnd = Ledger::getQualityNext(uDirectTip);
|
||||||
|
|
||||||
|
bool bBridge = true; // True, if bridging active. False, missing an offer.
|
||||||
|
uint256 uBridgeQuality;
|
||||||
|
STAmount saBridgeIn; // Amount available.
|
||||||
|
STAmount saBridgeOut;
|
||||||
|
|
||||||
|
bool bInNext = true; // True, if need to load.
|
||||||
|
STAmount saInIn; // Amount available. Consumed in loop. Limited by offer funding.
|
||||||
|
STAmount saInOut;
|
||||||
|
uint256 uInTip; // Current entry.
|
||||||
|
uint256 uInEnd;
|
||||||
|
unsigned int uInEntry;
|
||||||
|
|
||||||
|
bool bOutNext = true;
|
||||||
|
STAmount saOutIn;
|
||||||
|
STAmount saOutOut;
|
||||||
|
uint256 uOutTip;
|
||||||
|
uint256 uOutEnd;
|
||||||
|
unsigned int uOutEntry;
|
||||||
|
|
||||||
|
saPay.zero();
|
||||||
|
saPay.setCurrency(uPayCurrency);
|
||||||
|
saPay.setIssuer(uPayIssuerID);
|
||||||
|
|
||||||
|
saNeed = saWanted;
|
||||||
|
|
||||||
|
if (!saWanted.isNative() && !uTakerCurrency.isZero())
|
||||||
|
{
|
||||||
|
// Bridging
|
||||||
|
uInTip = Ledger::getBookBase(uPayCurrency, uPayIssuerID, uint160(0), uint160(0));
|
||||||
|
uInEnd = Ledger::getQualityNext(uInTip);
|
||||||
|
uOutTip = Ledger::getBookBase(uint160(0), uint160(0), saWanted.getCurrency(), saWanted.getIssuer());
|
||||||
|
uOutEnd = Ledger::getQualityNext(uInTip);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (tenUNKNOWN == terResult)
|
||||||
|
{
|
||||||
|
if (saNeed == saWanted)
|
||||||
|
{
|
||||||
|
// Got all.
|
||||||
|
saGot = saWanted;
|
||||||
|
terResult = terSUCCESS;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Calculate next tips, if needed.
|
||||||
|
|
||||||
|
if (bDirectNext)
|
||||||
|
{
|
||||||
|
// Find next direct offer.
|
||||||
|
uDirectTip = mLedger->getNextLedgerIndex(uDirectTip, uDirectEnd);
|
||||||
|
if (!!uDirectTip)
|
||||||
|
{
|
||||||
|
sleDirectDir = entryCache(ltDIR_NODE, uDirectTip);
|
||||||
|
|
||||||
|
// XXX Need to calculate the real quality: including fees.
|
||||||
|
uDirectQuality = STAmount::getQualityNext(uDirectTip);
|
||||||
|
}
|
||||||
|
|
||||||
|
bDirectNext = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bBridge && (bInNext || bOutNext))
|
||||||
|
{
|
||||||
|
// Bridging and need to calculate next bridge rate.
|
||||||
|
// A bridge can consist of multiple offers. As offer's are consumed, the effective rate changes.
|
||||||
|
|
||||||
|
if (bInNext)
|
||||||
|
{
|
||||||
|
// sleInDir = entryCache(ltDIR_NODE, mLedger->getNextLedgerIndex(uInIndex, uInEnd));
|
||||||
|
// Get the next funded offer.
|
||||||
|
offerBridgeNext(uInIndex, uInEnd, uInEntry, saInIn, saInOut); // Get offer limited by funding.
|
||||||
|
bInNext = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bOutNext)
|
||||||
|
{
|
||||||
|
// sleOutDir = entryCache(ltDIR_NODE, mLedger->getNextLedgerIndex(uOutIndex, uOutEnd));
|
||||||
|
offerNext(uOutIndex, uOutEnd, uOutEntry, saOutIn, saOutOut);
|
||||||
|
bOutNext = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!uInIndex || !uOutIndex)
|
||||||
|
{
|
||||||
|
bBridge = false; // No more offers to bridge.
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Have bridge in and out entries.
|
||||||
|
// Calculate bridge rate. Out offer pay ripple fee. In offer fee is added to in cost.
|
||||||
|
|
||||||
|
saBridgeOut.zero();
|
||||||
|
|
||||||
|
if (saInOut < saOutIn)
|
||||||
|
{
|
||||||
|
// Limit by in.
|
||||||
|
|
||||||
|
// XXX Need to include fees in saBridgeIn.
|
||||||
|
saBridgeIn = saInIn; // All of in
|
||||||
|
// Limit bridge out: saInOut/saBridgeOut = saOutIn/saOutOut
|
||||||
|
// Round such that we would take all of in offer, otherwise would have leftovers.
|
||||||
|
saBridgeOut = (saInOut * saOutOut) / saOutIn;
|
||||||
|
}
|
||||||
|
else if (saInOut > saOutIn)
|
||||||
|
{
|
||||||
|
// Limit by out, if at all.
|
||||||
|
|
||||||
|
// XXX Need to include fees in saBridgeIn.
|
||||||
|
// Limit bridge in:saInIn/saInOuts = aBridgeIn/saOutIn
|
||||||
|
// Round such that would take all of out offer.
|
||||||
|
saBridgeIn = (saInIn * saOutIn) / saInOuts;
|
||||||
|
saBridgeOut = saOutOut; // All of out.
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Entries match,
|
||||||
|
|
||||||
|
// XXX Need to include fees in saBridgeIn.
|
||||||
|
saBridgeIn = saInIn; // All of in
|
||||||
|
saBridgeOut = saOutOut; // All of out.
|
||||||
|
}
|
||||||
|
|
||||||
|
uBridgeQuality = STAmount::getRate(saBridgeIn, saBridgeOut); // Inclusive of fees.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bBridge)
|
||||||
|
{
|
||||||
|
bUseBridge = !uDirectTip || (uBridgeQuality < uDirectQuality)
|
||||||
|
}
|
||||||
|
else if (!!uDirectTip)
|
||||||
|
{
|
||||||
|
bUseBridge = false
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// No more offers. Declare success, even if none returned.
|
||||||
|
saGot = saWanted-saNeed;
|
||||||
|
terResult = terSUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (terSUCCESS != terResult)
|
||||||
|
{
|
||||||
|
STAmount& saAvailIn = bUseBridge ? saBridgeIn : saDirectIn;
|
||||||
|
STAmount& saAvailOut = bUseBridge ? saBridgeOut : saDirectOut;
|
||||||
|
|
||||||
|
if (saAvailOut > saNeed)
|
||||||
|
{
|
||||||
|
// Consume part of offer. Done.
|
||||||
|
|
||||||
|
saNeed = 0;
|
||||||
|
saPay += (saNeed*saAvailIn)/saAvailOut; // Round up, prefer to pay more.
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Consume entire offer.
|
||||||
|
|
||||||
|
saNeed -= saAvailOut;
|
||||||
|
saPay += saAvailIn;
|
||||||
|
|
||||||
|
if (bUseBridge)
|
||||||
|
{
|
||||||
|
// Consume bridge out.
|
||||||
|
if (saOutOut == saAvailOut)
|
||||||
|
{
|
||||||
|
// Consume all.
|
||||||
|
saOutOut = 0;
|
||||||
|
saOutIn = 0;
|
||||||
|
bOutNext = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Consume portion of bridge out, must be consuming all of bridge in.
|
||||||
|
// saOutIn/saOutOut = saSpent/saAvailOut
|
||||||
|
// Round?
|
||||||
|
saOutIn -= (saOutIn*saAvailOut)/saOutOut;
|
||||||
|
saOutOut -= saAvailOut;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Consume bridge in.
|
||||||
|
if (saOutIn == saAvailIn)
|
||||||
|
{
|
||||||
|
// Consume all.
|
||||||
|
saInOut = 0;
|
||||||
|
saInIn = 0;
|
||||||
|
bInNext = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Consume portion of bridge in, must be consuming all of bridge out.
|
||||||
|
// saInIn/saInOut = saAvailIn/saPay
|
||||||
|
// Round?
|
||||||
|
saInOut -= (saInOut*saAvailIn)/saInIn;
|
||||||
|
saInIn -= saAvailIn;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bDirectNext = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// From the destination work towards the source calculating how much must be asked for.
|
// From the destination work towards the source calculating how much must be asked for.
|
||||||
// --> bAllowPartial: If false, fail if can't meet requirements.
|
// --> bAllowPartial: If false, fail if can't meet requirements.
|
||||||
// <-- bSuccess: true=success, false=insufficient funds.
|
// <-- bSuccess: true=success, false=insufficient funds.
|
||||||
@@ -1570,63 +1991,112 @@ TransactionEngineResult calcOfferFill(paymentNode& pnSrc, paymentNode& pnDst, bo
|
|||||||
// --> [all]saWanted.mCurrency
|
// --> [all]saWanted.mCurrency
|
||||||
// --> [all]saAccount
|
// --> [all]saAccount
|
||||||
// <-> [0]saWanted.mAmount : --> limit, <-- actual
|
// <-> [0]saWanted.mAmount : --> limit, <-- actual
|
||||||
|
// XXX Disallow looping.
|
||||||
|
// XXX With multiple path and due to offers, must consider consumed.
|
||||||
bool calcPaymentReverse(std::vector<paymentNode>& pnNodes, bool bAllowPartial)
|
bool calcPaymentReverse(std::vector<paymentNode>& pnNodes, bool bAllowPartial)
|
||||||
{
|
{
|
||||||
bool bDone = false;
|
TransactionEngineResult terResult = tenUNKNOWN;
|
||||||
bool bSuccess = false;
|
|
||||||
|
|
||||||
// path: dst .. src
|
uIndex = pnNodes.size();
|
||||||
|
|
||||||
while (!bDone)
|
while (tenUNKNOWN == terResult && uIndex--)
|
||||||
{
|
{
|
||||||
if (cur->saWanted.isZero())
|
// Calculate (1) sending by fullfilling next wants and (2) setting current wants.
|
||||||
|
|
||||||
|
paymentNode& curPN = pnNodes[uIndex];
|
||||||
|
paymentNode& prvPN = pnNodes[uIndex-1];
|
||||||
|
paymentNode& nxtPN = pnNodes[uIndex+1];
|
||||||
|
|
||||||
|
if (!(uFlags & (PF_REDEEM|PF_ISSUE)))
|
||||||
|
{
|
||||||
|
// Redeem IOUs
|
||||||
|
terResult = tenBAD_PATH;
|
||||||
|
}
|
||||||
|
else if (curPN.saWanted.isZero())
|
||||||
{
|
{
|
||||||
// Must want something.
|
// Must want something.
|
||||||
terResult = terINVALID;
|
terResult = tenBAD_AMOUNT;
|
||||||
bDone = true;
|
|
||||||
}
|
}
|
||||||
else if (cur->saWanted.isNative())
|
else if (curPN->uFlags & PF_ACCOUNT)
|
||||||
{
|
{
|
||||||
if (prv->how == direct)
|
// Account node.
|
||||||
|
// Rippling through this accounts balances.
|
||||||
|
// No currency change.
|
||||||
|
// Issuer change possible.
|
||||||
|
|
||||||
|
SLE::pointer sleRippleCur = ;
|
||||||
|
SLE::pointer sleRippleNxt = ;
|
||||||
|
STAmount saBalanceCur = ;
|
||||||
|
|
||||||
|
if ((uFlags & PF_REDEEM) && saBalanceCur.isPositive())
|
||||||
{
|
{
|
||||||
// Stamp transfer desired.
|
// Redeem IOUs
|
||||||
if (prv->prev())
|
|
||||||
{
|
// XXX
|
||||||
// Stamp transfer can not have previous entries. Only stamp ripple can.
|
curPN.saWanted += ___;
|
||||||
terResult = terINVALID;
|
|
||||||
bDone = true;
|
bSent = true;
|
||||||
}
|
}
|
||||||
else if (prv->account->saBalance() >= cur->saWanted)
|
|
||||||
|
if ((uFlags & PF_ISSUE) // Allowed to issue.
|
||||||
|
&& !saWantedNxt.isZero() // Need to issue.
|
||||||
|
&& !saBalanceCur.isPositive()) // Can issue.
|
||||||
{
|
{
|
||||||
// Transfer stamps.
|
// Issue IOUs
|
||||||
prv->saSend = cur->saWanted;
|
|
||||||
bDone = true;
|
// XXX
|
||||||
bSuccess = true;
|
curPN.saWanted += ___;
|
||||||
|
bSent = true;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
// Insufficient funds for transfer
|
|
||||||
bDone = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Must convert to stamps via offer.
|
|
||||||
if (calcOfferFill(prv, cur, bAllowPartial))
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
else if (curPN->uFlags & PF_OFFER)
|
||||||
{
|
{
|
||||||
bDone = false;
|
// Offer node.
|
||||||
}
|
// Ripple or transfering from previous node through this offer to next node.
|
||||||
}
|
// Current node has a credit line with next node.
|
||||||
}
|
// Next node will receive either its own IOUs or this nodes IOUs.
|
||||||
else
|
// We limit what this node sends by this nodes redeem and issue max.
|
||||||
{
|
// This allows path lists to be strictly redeem.
|
||||||
// Rippling.
|
// XXX Make sure offer book was not previously mentioned.
|
||||||
|
|
||||||
|
uint160 uPrvCurrency = curPN->uFlags & PF_WANTED_CURRENCY
|
||||||
|
? curPN->saWanted.getCurrency()
|
||||||
|
: saSendMax.getCurrency();
|
||||||
|
|
||||||
|
uint160 uPrvIssuer = curPN->uFlags & PF_WANTED_ISSUER
|
||||||
|
? curPN->saWanted.getIssuer()
|
||||||
|
: saSendMax.getIssuer();
|
||||||
|
|
||||||
|
calcNodeOfferReverse(
|
||||||
|
uTakerCurrency,
|
||||||
|
uTakerIssuer,
|
||||||
|
nxtPN->saWanted, // Driver.
|
||||||
|
|
||||||
|
uTakerPaid,
|
||||||
|
uTakerGot,
|
||||||
|
uOwnerPaid,
|
||||||
|
uOwnerGot,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (uOwnerPaid.isZero())
|
||||||
|
{
|
||||||
|
terResult = terZERO; // Path contributes nothing.
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Update wanted.
|
||||||
|
|
||||||
|
// Save sent amount
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tenUNKNOWN == terResult == curPN.saWanted.isZero())
|
||||||
|
terResult = terZERO; // Path contributes nothing.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1850,6 +2320,8 @@ TransactionEngineResult TransactionEngine::doPayment(const SerializedTransaction
|
|||||||
return tenRIPPLE_EMPTY;
|
return tenRIPPLE_EMPTY;
|
||||||
}
|
}
|
||||||
#if 0
|
#if 0
|
||||||
|
// 1) Calc payment in reverse: do not modify sles.
|
||||||
|
// 2) Calc payment forward: do modify sles.
|
||||||
std::vector<STPath> spPath;
|
std::vector<STPath> spPath;
|
||||||
|
|
||||||
BOOST_FOREACH(std::vector<STPath>& spPath, spsPaths)
|
BOOST_FOREACH(std::vector<STPath>& spPath, spsPaths)
|
||||||
@@ -2023,10 +2495,11 @@ TransactionEngineResult TransactionEngine::takeOffers(
|
|||||||
// Have an offer to consider.
|
// Have an offer to consider.
|
||||||
Log(lsINFO) << "takeOffers: considering dir : " << sleOfferDir->getJson(0);
|
Log(lsINFO) << "takeOffers: considering dir : " << sleOfferDir->getJson(0);
|
||||||
|
|
||||||
|
SLE::pointer sleBookNode;
|
||||||
|
unsigned int uBookEntry;
|
||||||
uint256 uOfferIndex;
|
uint256 uOfferIndex;
|
||||||
uint64 uOfferNode;
|
|
||||||
|
|
||||||
dirFirst(uTipIndex, uOfferIndex, uOfferNode);
|
dirFirst(uTipIndex, sleBookNode, uBookEntry, uOfferIndex);
|
||||||
|
|
||||||
SLE::pointer sleOffer = entryCache(ltOFFER, uOfferIndex);
|
SLE::pointer sleOffer = entryCache(ltOFFER, uOfferIndex);
|
||||||
|
|
||||||
|
|||||||
@@ -123,21 +123,28 @@ private:
|
|||||||
const uint256& uRootIndex,
|
const uint256& uRootIndex,
|
||||||
const uint256& uLedgerIndex); // Item being deleted
|
const uint256& uLedgerIndex); // Item being deleted
|
||||||
|
|
||||||
void dirFirst(const uint256& uRootIndex, uint256& uEntryIndex, uint64& uEntryNode);
|
bool dirFirst(const uint256& uRootIndex, SLE::pointer& sleNode, unsigned int& uDirEntry, uint256& uEntryIndex);
|
||||||
|
bool dirNext(const uint256& uRootIndex, SLE::pointer& sleNode, unsigned int& uDirEntry, uint256& uEntryIndex);
|
||||||
|
|
||||||
#ifdef WORK_IN_PROGRESS
|
#ifdef WORK_IN_PROGRESS
|
||||||
typedef struct {
|
typedef struct {
|
||||||
STAmount saWanted; // What this node wants from upstream.
|
uint16 uFlags; // --> from path
|
||||||
|
|
||||||
STAmount saIOURedeem; // What this node will redeem downstream.
|
STAccount saAccount; // --> recieving/sending account
|
||||||
STAmount saIOUIssue; // What this node will issue downstream.
|
|
||||||
STAmount saSend; // Amount of stamps this node will send.
|
STAmount saWanted; // --> What this node wants from upstream.
|
||||||
|
|
||||||
|
// Maybe this should just be a bool:
|
||||||
|
STAmount saIOURedeemMax; // --> Max amount of IOUs to redeem downstream.
|
||||||
|
// Maybe this should just be a bool:
|
||||||
|
STAmount saIOUIssueMax; // --> Max Amount of IOUs to issue downstream.
|
||||||
|
|
||||||
|
STAmount saIOURedeem; // <-- What this node will redeem downstream.
|
||||||
|
STAmount saIOUIssue; // <-- What this node will issue downstream.
|
||||||
|
STAmount saSend; // <-- Stamps this node will send downstream.
|
||||||
|
|
||||||
STAmount saIOUForgive; // Amount of IOUs to forgive.
|
|
||||||
STAmount saIOUAccept; // Amount of IOUs to accept.
|
|
||||||
STAmount saRecieve; // Amount stamps to receive.
|
STAmount saRecieve; // Amount stamps to receive.
|
||||||
|
|
||||||
STAccount saAccount;
|
|
||||||
} paymentNode;
|
} paymentNode;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|||||||
@@ -27,11 +27,10 @@ TransactionFormat InnerTxnFormats[]=
|
|||||||
{ "CreditSet", ttCREDIT_SET, {
|
{ "CreditSet", ttCREDIT_SET, {
|
||||||
{ S_FIELD(Flags), STI_UINT32, SOE_FLAGS, 0 },
|
{ S_FIELD(Flags), STI_UINT32, SOE_FLAGS, 0 },
|
||||||
{ S_FIELD(Destination), STI_ACCOUNT, SOE_REQUIRED, 0 },
|
{ S_FIELD(Destination), STI_ACCOUNT, SOE_REQUIRED, 0 },
|
||||||
{ S_FIELD(LimitAmount), STI_AMOUNT, SOE_REQUIRED, 0 },
|
{ S_FIELD(SourceTag), STI_UINT32, SOE_IFFLAG, 1 },
|
||||||
{ S_FIELD(AcceptRate), STI_UINT32, SOE_IFFLAG, 1 },
|
{ S_FIELD(LimitAmount), STI_AMOUNT, SOE_IFFLAG, 2 },
|
||||||
{ S_FIELD(AcceptStart), STI_UINT32, SOE_IFFLAG, 2 },
|
{ S_FIELD(QualityIn), STI_UINT32, SOE_IFFLAG, 4 },
|
||||||
{ S_FIELD(AcceptExpire), STI_UINT32, SOE_IFFLAG, 4 },
|
{ S_FIELD(QualityOut), STI_UINT32, SOE_IFFLAG, 8 },
|
||||||
{ S_FIELD(SourceTag), STI_UINT32, SOE_IFFLAG, 8 },
|
|
||||||
{ S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x02000000 },
|
{ S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x02000000 },
|
||||||
{ sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } }
|
{ sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } }
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ void printHelp(const po::options_description& desc)
|
|||||||
cout << " password_set <master_seed> <regular_seed> [<account>]" << endl;
|
cout << " password_set <master_seed> <regular_seed> [<account>]" << endl;
|
||||||
cout << " peers" << endl;
|
cout << " peers" << endl;
|
||||||
cout << " ripple_lines_get <account>|<nickname>|<account_public_key> [<index>]" << endl;
|
cout << " ripple_lines_get <account>|<nickname>|<account_public_key> [<index>]" << endl;
|
||||||
cout << " ripple_line_set <seed> <paying_account> <destination_account> <limit_amount> <currency> [<account_rate>]" << endl;
|
cout << " ripple_line_set <seed> <paying_account> <destination_account> <limit_amount> <currency> [<quality_in>] [<quality_out>]" << endl;
|
||||||
cout << " send <seed> <paying_account> <account_id> <amount> [<currency>] [<send_max>] [<send_currency>]" << endl;
|
cout << " send <seed> <paying_account> <account_id> <amount> [<currency>] [<send_max>] [<send_currency>]" << endl;
|
||||||
cout << " stop" << endl;
|
cout << " stop" << endl;
|
||||||
cout << " tx <id>" << endl;
|
cout << " tx <id>" << endl;
|
||||||
|
|||||||
Reference in New Issue
Block a user