mirror of
https://github.com/XRPLF/rippled.git
synced 2025-11-26 22:15:52 +00:00
Revise trust set transactor for reserves.
This commit is contained in:
@@ -54,7 +54,7 @@ bool transResultInfo(TER terCode, std::string& strToken, std::string& strHuman)
|
|||||||
{ terNO_DST, "terNO_DST", "Destination does not exist. Send XRP to create it." },
|
{ terNO_DST, "terNO_DST", "Destination does not exist. Send XRP to create it." },
|
||||||
{ terNO_DST_INSUF_XRP, "terNO_DST_INSUF_XRP", "Destination does not exist. Too little XRP sent to create it." },
|
{ terNO_DST_INSUF_XRP, "terNO_DST_INSUF_XRP", "Destination does not exist. Too little XRP sent to create it." },
|
||||||
{ terNO_LINE, "terNO_LINE", "No such line." },
|
{ terNO_LINE, "terNO_LINE", "No such line." },
|
||||||
{ terNO_LINE_NO_ZERO, "terNO_LINE_NO_ZERO", "Can't zero non-existant line, destination might make it." },
|
{ terNO_LINE_REDUNDANT, "terNO_LINE_REDUNDANT", "Can't set non-existant line to default." },
|
||||||
{ terPRE_SEQ, "terPRE_SEQ", "Missing/inapplicable prior transaction." },
|
{ terPRE_SEQ, "terPRE_SEQ", "Missing/inapplicable prior transaction." },
|
||||||
{ terSET_MISSING_DST, "terSET_MISSING_DST", "Can't set password, destination missing." },
|
{ terSET_MISSING_DST, "terSET_MISSING_DST", "Can't set password, destination missing." },
|
||||||
{ terUNFUNDED, "terUNFUNDED", "Source account had insufficient balance for transaction." },
|
{ terUNFUNDED, "terUNFUNDED", "Source account had insufficient balance for transaction." },
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ enum TER // aka TransactionEngineResult
|
|||||||
terNO_DST,
|
terNO_DST,
|
||||||
terNO_DST_INSUF_XRP,
|
terNO_DST_INSUF_XRP,
|
||||||
terNO_LINE,
|
terNO_LINE,
|
||||||
terNO_LINE_NO_ZERO,
|
terNO_LINE_REDUNDANT,
|
||||||
terPRE_SEQ,
|
terPRE_SEQ,
|
||||||
terSET_MISSING_DST,
|
terSET_MISSING_DST,
|
||||||
terUNFUNDED,
|
terUNFUNDED,
|
||||||
|
|||||||
@@ -9,13 +9,19 @@ TER TrustSetTransactor::doApply()
|
|||||||
|
|
||||||
const STAmount saLimitAmount = mTxn.getFieldAmount(sfLimitAmount);
|
const STAmount saLimitAmount = mTxn.getFieldAmount(sfLimitAmount);
|
||||||
const bool bQualityIn = mTxn.isFieldPresent(sfQualityIn);
|
const bool bQualityIn = mTxn.isFieldPresent(sfQualityIn);
|
||||||
const uint32 uQualityIn = bQualityIn ? mTxn.getFieldU32(sfQualityIn) : 0;
|
|
||||||
const bool bQualityOut = mTxn.isFieldPresent(sfQualityOut);
|
const bool bQualityOut = mTxn.isFieldPresent(sfQualityOut);
|
||||||
const uint32 uQualityOut = bQualityIn ? mTxn.getFieldU32(sfQualityOut) : 0;
|
|
||||||
const uint160 uCurrencyID = saLimitAmount.getCurrency();
|
const uint160 uCurrencyID = saLimitAmount.getCurrency();
|
||||||
uint160 uDstAccountID = saLimitAmount.getIssuer();
|
uint160 uDstAccountID = saLimitAmount.getIssuer();
|
||||||
const bool bFlipped = mTxnAccountID > uDstAccountID; // true, iff current is not lowest.
|
const bool bFlipped = mTxnAccountID > uDstAccountID; // true, iff current is not lowest.
|
||||||
bool bDelIndex = false;
|
|
||||||
|
uint32 uQualityIn = bQualityIn ? mTxn.getFieldU32(sfQualityIn) : 0;
|
||||||
|
uint32 uQualityOut = bQualityIn ? mTxn.getFieldU32(sfQualityOut) : 0;
|
||||||
|
|
||||||
|
if (bQualityIn && QUALITY_ONE == uQualityIn)
|
||||||
|
uQualityIn = 0;
|
||||||
|
|
||||||
|
if (bQualityOut && QUALITY_ONE == uQualityOut)
|
||||||
|
uQualityOut = 0;
|
||||||
|
|
||||||
// Check if destination makes sense.
|
// Check if destination makes sense.
|
||||||
|
|
||||||
@@ -52,77 +58,198 @@ TER TrustSetTransactor::doApply()
|
|||||||
SLE::pointer sleRippleState = mEngine->entryCache(ltRIPPLE_STATE, Ledger::getRippleStateIndex(mTxnAccountID, uDstAccountID, uCurrencyID));
|
SLE::pointer sleRippleState = mEngine->entryCache(ltRIPPLE_STATE, Ledger::getRippleStateIndex(mTxnAccountID, uDstAccountID, uCurrencyID));
|
||||||
if (sleRippleState)
|
if (sleRippleState)
|
||||||
{
|
{
|
||||||
// A line exists in one or more directions.
|
STAmount saLowBalance;
|
||||||
|
STAmount saLowLimit;
|
||||||
|
STAmount saHighBalance;
|
||||||
|
STAmount saHighLimit;
|
||||||
|
uint32 uLowQualityIn;
|
||||||
|
uint32 uLowQualityOut;
|
||||||
|
uint32 uHighQualityIn;
|
||||||
|
uint32 uHighQualityOut;
|
||||||
|
const uint160& uLowAccountID = !bFlipped ? mTxnAccountID : uDstAccountID;
|
||||||
|
const uint160& uHighAccountID = bFlipped ? mTxnAccountID : uDstAccountID;
|
||||||
|
SLE::ref sleLowAccount = !bFlipped ? mTxnAccount : sleDst;
|
||||||
|
SLE::ref sleHighAccount = bFlipped ? mTxnAccount : sleDst;
|
||||||
|
|
||||||
#if 0
|
//
|
||||||
// We might delete a ripple state node if everything is set to defaults.
|
// Balances
|
||||||
// However, this is problematic as it may make predicting reserve amounts harder for users.
|
//
|
||||||
// The code here is incomplete.
|
|
||||||
|
|
||||||
if (!saLimitAmount)
|
saLowBalance = sleRippleState->getFieldAmount(sfBalance);
|
||||||
|
saHighBalance = saLowBalance;
|
||||||
|
|
||||||
|
if (bFlipped)
|
||||||
{
|
{
|
||||||
// Zeroing line.
|
saLowBalance.negate();
|
||||||
uint160 uLowID = sleRippleState->getFieldAmount(sfLowLimit).getIssuer();
|
|
||||||
uint160 uHighID = sleRippleState->getFieldAmount(sfHighLimit).getIssuer();
|
|
||||||
bool bLow = uLowID == uSrcAccountID;
|
|
||||||
bool bHigh = uLowID == uDstAccountID;
|
|
||||||
bool bBalanceZero = !sleRippleState->getFieldAmount(sfBalance);
|
|
||||||
STAmount saDstLimit = sleRippleState->getFieldAmount(bSendLow ? sfLowLimit : sfHighLimit);
|
|
||||||
bool bDstLimitZero = !saDstLimit;
|
|
||||||
|
|
||||||
assert(bLow || bHigh);
|
|
||||||
|
|
||||||
if (bBalanceZero && bDstLimitZero)
|
|
||||||
{
|
|
||||||
// Zero balance and eliminating last limit.
|
|
||||||
|
|
||||||
bDelIndex = true;
|
|
||||||
terResult = dirDelete(false, uSrcRef, Ledger::getOwnerDirIndex(mTxnAccountID), sleRippleState->getIndex(), false);
|
|
||||||
}
|
}
|
||||||
}
|
else
|
||||||
#endif
|
|
||||||
|
|
||||||
if (!bDelIndex)
|
|
||||||
{
|
{
|
||||||
sleRippleState->setFieldAmount(bFlipped ? sfHighLimit: sfLowLimit, saLimitAllow);
|
saHighBalance.negate();
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Limits
|
||||||
|
//
|
||||||
|
|
||||||
|
if (bFlipped)
|
||||||
|
{
|
||||||
|
sleRippleState->setFieldAmount(sfHighLimit, saLimitAllow);
|
||||||
|
|
||||||
|
saLowLimit = sleRippleState->getFieldAmount(sfLowLimit);
|
||||||
|
saHighLimit = saLimitAllow;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sleRippleState->setFieldAmount(sfLowLimit, saLimitAllow);
|
||||||
|
|
||||||
|
saLowLimit = saLimitAllow;
|
||||||
|
saHighLimit = sleRippleState->getFieldAmount(sfHighLimit);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Quality in
|
||||||
|
//
|
||||||
|
|
||||||
if (!bQualityIn)
|
if (!bQualityIn)
|
||||||
{
|
{
|
||||||
nothing();
|
// Not setting. Just get it.
|
||||||
|
|
||||||
|
uLowQualityIn = sleRippleState->getFieldU32(sfLowQualityIn);
|
||||||
|
uHighQualityIn = sleRippleState->getFieldU32(sfHighQualityIn);
|
||||||
}
|
}
|
||||||
else if (uQualityIn)
|
else if (uQualityIn)
|
||||||
{
|
{
|
||||||
sleRippleState->setFieldU32(bFlipped ? sfLowQualityIn : sfHighQualityIn, uQualityIn);
|
// Setting.
|
||||||
|
|
||||||
|
sleRippleState->setFieldU32(!bFlipped ? sfLowQualityIn : sfHighQualityIn, uQualityIn);
|
||||||
|
|
||||||
|
uLowQualityIn = !bFlipped ? uQualityIn : sleRippleState->getFieldU32(sfLowQualityIn);
|
||||||
|
uHighQualityIn = bFlipped ? uQualityIn : sleRippleState->getFieldU32(sfHighQualityIn);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
sleRippleState->makeFieldAbsent(bFlipped ? sfLowQualityIn : sfHighQualityIn);
|
// Clearing.
|
||||||
|
|
||||||
|
sleRippleState->makeFieldAbsent(!bFlipped ? sfLowQualityIn : sfHighQualityIn);
|
||||||
|
|
||||||
|
uLowQualityIn = !bFlipped ? 0 : sleRippleState->getFieldU32(sfLowQualityIn);
|
||||||
|
uHighQualityIn = bFlipped ? 0 : sleRippleState->getFieldU32(sfHighQualityIn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Quality out
|
||||||
|
//
|
||||||
|
|
||||||
if (!bQualityOut)
|
if (!bQualityOut)
|
||||||
{
|
{
|
||||||
nothing();
|
// Not setting. Just get it.
|
||||||
|
|
||||||
|
uLowQualityOut = sleRippleState->getFieldU32(sfLowQualityOut);
|
||||||
|
uHighQualityOut = sleRippleState->getFieldU32(sfHighQualityOut);
|
||||||
}
|
}
|
||||||
else if (uQualityOut)
|
else if (uQualityOut)
|
||||||
{
|
{
|
||||||
sleRippleState->setFieldU32(bFlipped ? sfLowQualityOut : sfHighQualityOut, uQualityOut);
|
// Setting.
|
||||||
|
|
||||||
|
sleRippleState->setFieldU32(!bFlipped ? sfLowQualityOut : sfHighQualityOut, uQualityOut);
|
||||||
|
|
||||||
|
uLowQualityOut = !bFlipped ? uQualityOut : sleRippleState->getFieldU32(sfLowQualityOut);
|
||||||
|
uHighQualityOut = bFlipped ? uQualityOut : sleRippleState->getFieldU32(sfHighQualityOut);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
sleRippleState->makeFieldAbsent(bFlipped ? sfLowQualityOut : sfHighQualityOut);
|
// Clearing.
|
||||||
|
|
||||||
|
sleRippleState->makeFieldAbsent(!bFlipped ? sfLowQualityOut : sfHighQualityOut);
|
||||||
|
|
||||||
|
uLowQualityOut = !bFlipped ? 0 : sleRippleState->getFieldU32(sfLowQualityOut);
|
||||||
|
uHighQualityOut = bFlipped ? 0 : sleRippleState->getFieldU32(sfHighQualityOut);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (QUALITY_ONE == uLowQualityIn) uLowQualityIn = 0;
|
||||||
|
if (QUALITY_ONE == uHighQualityIn) uHighQualityIn = 0;
|
||||||
|
if (QUALITY_ONE == uLowQualityOut) uLowQualityOut = 0;
|
||||||
|
if (QUALITY_ONE == uHighQualityOut) uHighQualityOut = 0;
|
||||||
|
|
||||||
|
const bool bLowReserveSet = uLowQualityIn || uLowQualityOut || !!saLowLimit || saLowBalance.isPositive();
|
||||||
|
const bool bLowReserveClear = !uLowQualityIn && !uLowQualityOut && !saLowLimit && !saLowBalance.isPositive();
|
||||||
|
|
||||||
|
const bool bHighReserveSet = uHighQualityIn || uHighQualityOut || !!saHighLimit || saHighBalance.isPositive();
|
||||||
|
const bool bHighReserveClear = !uHighQualityIn && !uHighQualityOut && !saHighLimit && !saHighBalance.isPositive();
|
||||||
|
const bool bDefault = bLowReserveClear && bHighReserveClear;
|
||||||
|
|
||||||
|
const uint32 uFlagsIn = sleRippleState->getFieldU32(sfFlags);
|
||||||
|
uint32 uFlagsOut = uFlagsIn;
|
||||||
|
|
||||||
|
const bool bLowReserved = isSetBit(uFlagsIn, lsfLowReserve);
|
||||||
|
const bool bHighReserved = isSetBit(uFlagsIn, lsfHighReserve);
|
||||||
|
|
||||||
|
if (bLowReserveSet && !bLowReserved)
|
||||||
|
{
|
||||||
|
// Set reserve for low account.
|
||||||
|
|
||||||
|
terResult = mEngine->getNodes().ownerCountAdjust(uLowAccountID, 1, sleLowAccount);
|
||||||
|
uFlagsOut |= lsfLowReserve;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bLowReserveClear && bLowReserved)
|
||||||
|
{
|
||||||
|
// Clear reserve for low account.
|
||||||
|
|
||||||
|
terResult = mEngine->getNodes().ownerCountAdjust(uLowAccountID, -1, sleLowAccount);
|
||||||
|
uFlagsOut &= ~lsfLowReserve;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bHighReserveSet && !bHighReserved)
|
||||||
|
{
|
||||||
|
// Set reserve for high account.
|
||||||
|
|
||||||
|
terResult = mEngine->getNodes().ownerCountAdjust(uHighAccountID, 1, sleHighAccount);
|
||||||
|
uFlagsOut |= lsfHighReserve;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bHighReserveClear && bHighReserved)
|
||||||
|
{
|
||||||
|
// Clear reserve for high account.
|
||||||
|
|
||||||
|
terResult = mEngine->getNodes().ownerCountAdjust(uHighAccountID, -1, sleHighAccount);
|
||||||
|
uFlagsOut &= ~lsfHighReserve;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (uFlagsIn != uFlagsOut)
|
||||||
|
sleRippleState->setFieldU32(sfFlags, uFlagsOut);
|
||||||
|
|
||||||
|
if (bDefault)
|
||||||
|
{
|
||||||
|
// Can delete.
|
||||||
|
|
||||||
|
uint64 uSrcRef; // <-- Ignored, dirs never delete.
|
||||||
|
|
||||||
|
terResult = mEngine->getNodes().dirDelete(false, uSrcRef, Ledger::getOwnerDirIndex(uLowAccountID), sleRippleState->getIndex(), false);
|
||||||
|
|
||||||
|
if (tesSUCCESS == terResult)
|
||||||
|
terResult = mEngine->getNodes().dirDelete(false, uSrcRef, Ledger::getOwnerDirIndex(uHighAccountID), sleRippleState->getIndex(), false);
|
||||||
|
|
||||||
|
mEngine->entryDelete(sleRippleState);
|
||||||
|
|
||||||
|
Log(lsINFO) << "doTrustSet: Deleting ripple line";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
mEngine->entryModify(sleRippleState);
|
mEngine->entryModify(sleRippleState);
|
||||||
}
|
|
||||||
|
|
||||||
Log(lsINFO) << "doTrustSet: Modifying ripple line: bDelIndex=" << bDelIndex;
|
Log(lsINFO) << "doTrustSet: Modify ripple line";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Line does not exist.
|
// Line does not exist.
|
||||||
else if (!saLimitAmount)
|
else if (!saLimitAmount // Setting default limit.
|
||||||
|
&& bQualityIn && !uQualityIn // Setting default quality in.
|
||||||
|
&& bQualityOut && !uQualityOut // Setting default quality out.
|
||||||
|
)
|
||||||
{
|
{
|
||||||
Log(lsINFO) << "doTrustSet: Redundant: Setting non-existent ripple line to 0.";
|
Log(lsINFO) << "doTrustSet: Redundant: Setting non-existent ripple line to defaults.";
|
||||||
|
|
||||||
return terNO_LINE_NO_ZERO;
|
return terNO_LINE_REDUNDANT;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -132,13 +259,16 @@ TER TrustSetTransactor::doApply()
|
|||||||
Log(lsINFO) << "doTrustSet: Creating ripple line: " << sleRippleState->getIndex().ToString();
|
Log(lsINFO) << "doTrustSet: Creating ripple line: " << sleRippleState->getIndex().ToString();
|
||||||
|
|
||||||
sleRippleState->setFieldAmount(sfBalance, STAmount(uCurrencyID, ACCOUNT_ONE)); // Zero balance in currency.
|
sleRippleState->setFieldAmount(sfBalance, STAmount(uCurrencyID, ACCOUNT_ONE)); // Zero balance in currency.
|
||||||
sleRippleState->setFieldAmount(bFlipped ? sfHighLimit : sfLowLimit, saLimitAllow);
|
sleRippleState->setFieldAmount(!bFlipped ? sfLowLimit : sfHighLimit, saLimitAllow);
|
||||||
sleRippleState->setFieldAmount(bFlipped ? sfLowLimit : sfHighLimit, STAmount(uCurrencyID, uDstAccountID));
|
sleRippleState->setFieldAmount( bFlipped ? sfLowLimit : sfHighLimit, STAmount(uCurrencyID, uDstAccountID));
|
||||||
|
|
||||||
if (uQualityIn)
|
if (uQualityIn)
|
||||||
sleRippleState->setFieldU32(bFlipped ? sfHighQualityIn : sfLowQualityIn, uQualityIn);
|
sleRippleState->setFieldU32(!bFlipped ? sfLowQualityIn : sfHighQualityIn, uQualityIn);
|
||||||
|
|
||||||
if (uQualityOut)
|
if (uQualityOut)
|
||||||
sleRippleState->setFieldU32(bFlipped ? sfHighQualityOut : sfLowQualityOut, uQualityOut);
|
sleRippleState->setFieldU32(!bFlipped ? sfLowQualityOut : sfHighQualityOut, uQualityOut);
|
||||||
|
|
||||||
|
sleRippleState->setFieldU32(sfFlags, !bFlipped ? lsfLowReserve : lsfHighReserve);
|
||||||
|
|
||||||
uint64 uSrcRef; // <-- Ignored, dirs never delete.
|
uint64 uSrcRef; // <-- Ignored, dirs never delete.
|
||||||
|
|
||||||
@@ -157,9 +287,6 @@ TER TrustSetTransactor::doApply()
|
|||||||
Ledger::getOwnerDirIndex(uDstAccountID),
|
Ledger::getOwnerDirIndex(uDstAccountID),
|
||||||
sleRippleState->getIndex(),
|
sleRippleState->getIndex(),
|
||||||
boost::bind(&Ledger::ownerDirDescriber, _1, uDstAccountID));
|
boost::bind(&Ledger::ownerDirDescriber, _1, uDstAccountID));
|
||||||
|
|
||||||
if (tesSUCCESS == terResult)
|
|
||||||
terResult = mEngine->getNodes().ownerCountAdjust(uDstAccountID, 1, sleDst);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Log(lsINFO) << "doTrustSet<";
|
Log(lsINFO) << "doTrustSet<";
|
||||||
|
|||||||
Reference in New Issue
Block a user