mirror of
https://github.com/Xahau/xahaud.git
synced 2025-11-20 18:45:55 +00:00
Add trust auto clear. Fixes #28
This commit is contained in:
@@ -150,8 +150,9 @@ void LedgerEntrySet::entryCreate(SLE::ref sle)
|
||||
|
||||
case taaMODIFY:
|
||||
throw std::runtime_error("Create after modify");
|
||||
|
||||
case taaCREATE:
|
||||
throw std::runtime_error("Create after create"); // We could make this work
|
||||
throw std::runtime_error("Create after create"); // This could be made to work
|
||||
|
||||
case taaCACHED:
|
||||
throw std::runtime_error("Create after cache");
|
||||
@@ -532,7 +533,7 @@ TER LedgerEntrySet::dirCount(const uint256& uRootIndex, uint32& uCount)
|
||||
// <-- uNodeDir: For deletion, present to make dirDelete efficient.
|
||||
// --> uRootIndex: The index of the base of the directory. Nodes are based off of this.
|
||||
// --> uLedgerIndex: Value to add to directory.
|
||||
// We only append. This allow for things that watch append only structure to just monitor from the last node on ward.
|
||||
// Only append. This allow for things that watch append only structure to just monitor from the last node on ward.
|
||||
// Within a node with no deletions order of elements is sequential. Otherwise, order of elements is random.
|
||||
TER LedgerEntrySet::dirAdd(
|
||||
uint64& uNodeDir,
|
||||
@@ -850,7 +851,7 @@ bool LedgerEntrySet::dirFirst(
|
||||
sleNode = entryCache(ltDIR_NODE, uRootIndex);
|
||||
uDirEntry = 0;
|
||||
|
||||
assert(sleNode); // We never probe for directories.
|
||||
assert(sleNode); // Never probe for directories.
|
||||
|
||||
return LedgerEntrySet::dirNext(uRootIndex, sleNode, uDirEntry, uEntryIndex);
|
||||
}
|
||||
@@ -1243,13 +1244,38 @@ TER LedgerEntrySet::trustCreate(
|
||||
|
||||
ownerCountAdjust(!bSetDst ? uSrcAccountID : uDstAccountID, 1, sleAccount);
|
||||
|
||||
sleRippleState->setFieldAmount(sfBalance, bSetHigh ? -saBalance : saBalance);
|
||||
sleRippleState->setFieldAmount(sfBalance, bSetHigh ? -saBalance : saBalance); // ONLY: Create ripple balance.
|
||||
}
|
||||
|
||||
return terResult;
|
||||
}
|
||||
|
||||
// Direct send w/o fees: redeeming IOUs and/or sending own IOUs.
|
||||
TER LedgerEntrySet::trustDelete(SLE::ref sleRippleState, const uint160& uLowAccountID, const uint160& uHighAccountID)
|
||||
{
|
||||
bool bLowNode = sleRippleState->isFieldPresent(sfLowNode); // Detect legacy dirs.
|
||||
bool bHighNode = sleRippleState->isFieldPresent(sfHighNode);
|
||||
uint64 uLowNode = sleRippleState->getFieldU64(sfLowNode);
|
||||
uint64 uHighNode = sleRippleState->getFieldU64(sfHighNode);
|
||||
TER terResult;
|
||||
|
||||
cLog(lsTRACE) << "trustDelete: Deleting ripple line: low";
|
||||
terResult = dirDelete(false, uLowNode, Ledger::getOwnerDirIndex(uLowAccountID), sleRippleState->getIndex(), false, !bLowNode);
|
||||
|
||||
if (tesSUCCESS == terResult)
|
||||
{
|
||||
cLog(lsTRACE) << "trustDelete: Deleting ripple line: high";
|
||||
terResult = dirDelete(false, uHighNode, Ledger::getOwnerDirIndex(uHighAccountID), sleRippleState->getIndex(), false, !bHighNode);
|
||||
}
|
||||
|
||||
cLog(lsINFO) << "trustDelete: Deleting ripple line: state";
|
||||
entryDelete(sleRippleState);
|
||||
|
||||
return terResult;
|
||||
}
|
||||
|
||||
// Direct send w/o fees:
|
||||
// - Redeeming IOUs and/or sending sender's own IOUs.
|
||||
// - Create trust line of needed.
|
||||
TER LedgerEntrySet::rippleCredit(const uint160& uSenderID, const uint160& uReceiverID, const STAmount& saAmount, bool bCheckIssuer)
|
||||
{
|
||||
uint160 uIssuerID = saAmount.getIssuer();
|
||||
@@ -1306,15 +1332,47 @@ TER LedgerEntrySet::rippleCredit(const uint160& uSenderID, const uint160& uRecei
|
||||
% saAmount.getFullText()
|
||||
% saBalance.getFullText());
|
||||
|
||||
bool bDelete = false;
|
||||
uint32 uFlags;
|
||||
|
||||
// YYY Could skip this if rippling in reverse.
|
||||
if (saBefore.isPositive() // Sender balance was positive.
|
||||
&& !saBalance.isPositive() // Sender is zero or negative.
|
||||
&& isSetBit((uFlags = sleRippleState->getFieldU32(sfFlags)), !bSenderHigh ? lsfLowReserve : lsfHighReserve) // Sender reserve is set.
|
||||
&& !sleRippleState->getFieldAmount(!bSenderHigh ? sfLowLimit : sfHighLimit) // Sender trust limit is 0.
|
||||
&& !sleRippleState->getFieldU32(!bSenderHigh ? sfLowQualityIn : sfHighQualityIn) // Sender quality in is 0.
|
||||
&& !sleRippleState->getFieldU32(!bSenderHigh ? sfLowQualityOut : sfHighQualityOut)) // Sender quality out is 0.
|
||||
{
|
||||
// Clear the reserve of the sender, possibly delete the line!
|
||||
SLE::pointer sleSender = entryCache(ltACCOUNT_ROOT, Ledger::getAccountRootIndex(uSenderID));
|
||||
|
||||
ownerCountAdjust(uSenderID, -1, sleSender);
|
||||
|
||||
sleRippleState->setFieldU32(sfFlags, uFlags & (!bSenderHigh ? ~lsfLowReserve : ~lsfHighReserve)); // Clear reserve flag.
|
||||
|
||||
bDelete = !saBalance // Balance is zero.
|
||||
&& !isSetBit(uFlags, bSenderHigh ? lsfLowReserve : lsfHighReserve); // Receiver reserve is clear.
|
||||
}
|
||||
|
||||
if (bSenderHigh)
|
||||
saBalance.negate();
|
||||
|
||||
sleRippleState->setFieldAmount(sfBalance, saBalance);
|
||||
// Want to reflect balance to zero even if we are deleting line.
|
||||
sleRippleState->setFieldAmount(sfBalance, saBalance); // ONLY: Adjust ripple balance.
|
||||
|
||||
if (bDelete)
|
||||
{
|
||||
terResult = trustDelete(sleRippleState,
|
||||
bSenderHigh ? uReceiverID : uSenderID,
|
||||
!bSenderHigh ? uReceiverID : uSenderID);
|
||||
}
|
||||
else
|
||||
{
|
||||
entryModify(sleRippleState);
|
||||
|
||||
terResult = tesSUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
return terResult;
|
||||
}
|
||||
@@ -1374,6 +1432,7 @@ TER LedgerEntrySet::accountSend(const uint160& uSenderID, const uint160& uReceiv
|
||||
}
|
||||
else if (saAmount.isNative())
|
||||
{
|
||||
// XRP send which does not check reserve and can do pure adjustment.
|
||||
SLE::pointer sleSender = !!uSenderID
|
||||
? entryCache(ltACCOUNT_ROOT, Ledger::getAccountRootIndex(uSenderID))
|
||||
: SLE::pointer();
|
||||
@@ -1398,14 +1457,14 @@ TER LedgerEntrySet::accountSend(const uint160& uSenderID, const uint160& uReceiv
|
||||
}
|
||||
else
|
||||
{
|
||||
sleSender->setFieldAmount(sfBalance, sleSender->getFieldAmount(sfBalance) - saAmount);
|
||||
sleSender->setFieldAmount(sfBalance, sleSender->getFieldAmount(sfBalance) - saAmount); // Decrement XRP balance.
|
||||
entryModify(sleSender);
|
||||
}
|
||||
}
|
||||
|
||||
if (tesSUCCESS == terResult && sleReceiver)
|
||||
{
|
||||
sleReceiver->setFieldAmount(sfBalance, sleReceiver->getFieldAmount(sfBalance) + saAmount);
|
||||
sleReceiver->setFieldAmount(sfBalance, sleReceiver->getFieldAmount(sfBalance) + saAmount); // Increment XRP balance.
|
||||
entryModify(sleReceiver);
|
||||
}
|
||||
|
||||
|
||||
@@ -156,6 +156,7 @@ public:
|
||||
const STAmount& saSrcLimit,
|
||||
const uint32 uSrcQualityIn = 0,
|
||||
const uint32 uSrcQualityOut = 0);
|
||||
TER trustDelete(SLE::ref sleRippleState, const uint160& uLowAccountID, const uint160& uHighAccountID);
|
||||
|
||||
Json::Value getJson(int) const;
|
||||
void calcRawMeta(Serializer&, TER result, uint32 index);
|
||||
|
||||
@@ -252,22 +252,7 @@ TER TrustSetTransactor::doApply()
|
||||
{
|
||||
// Can delete.
|
||||
|
||||
bool bLowNode = sleRippleState->isFieldPresent(sfLowNode); // Detect legacy dirs.
|
||||
bool bHighNode = sleRippleState->isFieldPresent(sfHighNode);
|
||||
uint64 uLowNode = sleRippleState->getFieldU64(sfLowNode);
|
||||
uint64 uHighNode = sleRippleState->getFieldU64(sfHighNode);
|
||||
|
||||
cLog(lsTRACE) << "doTrustSet: Deleting ripple line: low";
|
||||
terResult = mEngine->getNodes().dirDelete(false, uLowNode, Ledger::getOwnerDirIndex(uLowAccountID), sleRippleState->getIndex(), false, !bLowNode);
|
||||
|
||||
if (tesSUCCESS == terResult)
|
||||
{
|
||||
cLog(lsTRACE) << "doTrustSet: Deleting ripple line: high";
|
||||
terResult = mEngine->getNodes().dirDelete(false, uHighNode, Ledger::getOwnerDirIndex(uHighAccountID), sleRippleState->getIndex(), false, !bHighNode);
|
||||
}
|
||||
|
||||
cLog(lsINFO) << "doTrustSet: Deleting ripple line: state";
|
||||
mEngine->entryDelete(sleRippleState);
|
||||
terResult = mEngine->getNodes().trustDelete(sleRippleState, uLowAccountID, uHighAccountID);
|
||||
}
|
||||
else if (bReserveIncrease
|
||||
&& mPriorBalance.getNValue() < uReserveCreate) // Reserve is not scaled by load.
|
||||
|
||||
@@ -1274,4 +1274,132 @@ buster.testCase("Quality paths", {
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
buster.testCase("Trust auto clear", {
|
||||
'setUp' : testutils.build_setup(),
|
||||
// 'setUp' : testutils.build_setup({ verbose: true }),
|
||||
// 'setUp' : testutils.build_setup({ verbose: true, no_server: true }),
|
||||
'tearDown' : testutils.build_teardown(),
|
||||
|
||||
"trust normal clear" :
|
||||
function (done) {
|
||||
var self = this;
|
||||
|
||||
async.waterfall([
|
||||
function (callback) {
|
||||
self.what = "Create accounts.";
|
||||
|
||||
testutils.create_accounts(self.remote, "root", "10000.0", ["alice", "bob"], callback);
|
||||
},
|
||||
function (callback) {
|
||||
self.what = "Set credit limits.";
|
||||
|
||||
// Mutual trust.
|
||||
testutils.credit_limits(self.remote,
|
||||
{
|
||||
"alice" : "1000/USD/bob",
|
||||
"bob" : "1000/USD/alice",
|
||||
},
|
||||
callback);
|
||||
},
|
||||
function (callback) {
|
||||
self.what = "Verify credit limits.";
|
||||
|
||||
testutils.verify_limit(self.remote, "bob", "1000/USD/alice", callback);
|
||||
},
|
||||
function (callback) {
|
||||
self.what = "Clear credit limits.";
|
||||
|
||||
// Mutual trust.
|
||||
testutils.credit_limits(self.remote,
|
||||
{
|
||||
"alice" : "0/USD/bob",
|
||||
"bob" : "0/USD/alice",
|
||||
},
|
||||
callback);
|
||||
},
|
||||
function (callback) {
|
||||
self.what = "Verify credit limits.";
|
||||
|
||||
testutils.verify_limit(self.remote, "bob", "0/USD/alice", function (m) {
|
||||
var success = m && 'remoteError' === m.error && 'entryNotFound' === m.remote.error;
|
||||
|
||||
callback(!success);
|
||||
});
|
||||
},
|
||||
// YYY Could verify owner counts are zero.
|
||||
], function (error) {
|
||||
buster.refute(error, self.what);
|
||||
done();
|
||||
});
|
||||
},
|
||||
|
||||
"trust auto clear" :
|
||||
function (done) {
|
||||
var self = this;
|
||||
|
||||
async.waterfall([
|
||||
function (callback) {
|
||||
self.what = "Create accounts.";
|
||||
|
||||
testutils.create_accounts(self.remote, "root", "10000.0", ["alice", "bob"], callback);
|
||||
},
|
||||
function (callback) {
|
||||
self.what = "Set credit limits.";
|
||||
|
||||
// Mutual trust.
|
||||
testutils.credit_limits(self.remote,
|
||||
{
|
||||
"alice" : "1000/USD/bob",
|
||||
},
|
||||
callback);
|
||||
},
|
||||
function (callback) {
|
||||
self.what = "Distribute funds.";
|
||||
|
||||
testutils.payments(self.remote,
|
||||
{
|
||||
"bob" : [ "50/USD/alice" ],
|
||||
},
|
||||
callback);
|
||||
},
|
||||
function (callback) {
|
||||
self.what = "Clear credit limits.";
|
||||
|
||||
// Mutual trust.
|
||||
testutils.credit_limits(self.remote,
|
||||
{
|
||||
"alice" : "0/USD/bob",
|
||||
},
|
||||
callback);
|
||||
},
|
||||
function (callback) {
|
||||
self.what = "Verify credit limits.";
|
||||
|
||||
testutils.verify_limit(self.remote, "alice", "0/USD/bob", callback);
|
||||
},
|
||||
function (callback) {
|
||||
self.what = "Return funds.";
|
||||
|
||||
testutils.payments(self.remote,
|
||||
{
|
||||
"alice" : [ "50/USD/bob" ],
|
||||
},
|
||||
callback);
|
||||
},
|
||||
function (callback) {
|
||||
self.what = "Verify credit limit gone.";
|
||||
|
||||
testutils.verify_limit(self.remote, "bob", "0/USD/alice", function (m) {
|
||||
var success = m && 'remoteError' === m.error && 'entryNotFound' === m.remote.error;
|
||||
|
||||
callback(!success);
|
||||
});
|
||||
},
|
||||
], function (error) {
|
||||
buster.refute(error, self.what);
|
||||
done();
|
||||
});
|
||||
},
|
||||
});
|
||||
// vim:sw=2:sts=2:ts=8:et
|
||||
|
||||
@@ -226,7 +226,7 @@ var verify_limit = function (remote, src, amount, callback) {
|
||||
|
||||
callback();
|
||||
})
|
||||
.on('error', function (m) {
|
||||
.once('error', function (m) {
|
||||
// console.log("error: %s", JSON.stringify(m));
|
||||
|
||||
callback(m);
|
||||
|
||||
Reference in New Issue
Block a user