mirror of
https://github.com/XRPLF/rippled.git
synced 2025-12-06 17:27:55 +00:00
Improve transaction error condition handling (RIPD-1578, RIPD-1593):
As described in #2314, when an offer executed with `Fill or Kill` semantics, the server would return `tesSUCCESS` even if the order couldn't be filled and was aborted. This would require additional processing of metadata by users to determine the effects of the transaction. This commit introduces the `fix1578` amendment which, if enabled, will cause the server to return the new `tecKILLED` error code instead of `tesSUCCESS` for `Fill or Kill` orders that could not be filled. Additionally, the `fix1578` amendment will prevent the setting of the `No Ripple` flag on trust lines with negative balance; trying to set the flag on such a trust line will fail with the new error code `tecNEGATIVE_BALANCE`.
This commit is contained in:
committed by
Nik Bougalis
parent
4dcb3c9199
commit
4104778067
@@ -56,7 +56,8 @@ public:
|
||||
env.close();
|
||||
|
||||
// Check no-ripple flag on sender 'gateway'
|
||||
auto lines = env.rpc("json", "account_lines", to_string(account_gw));
|
||||
Json::Value lines {env.rpc(
|
||||
"json", "account_lines", to_string(account_gw))};
|
||||
auto const& gline0 = lines[jss::result][jss::lines][0u];
|
||||
BEAST_EXPECT(gline0[jss::no_ripple].asBool() == SetOrClear);
|
||||
|
||||
@@ -72,45 +73,92 @@ public:
|
||||
testcase("Set noripple on a line with negative balance");
|
||||
|
||||
using namespace jtx;
|
||||
Env env(*this, features);
|
||||
|
||||
auto const gw = Account("gateway");
|
||||
auto const alice = Account("alice");
|
||||
auto const bob = Account("bob");
|
||||
auto const carol = Account("carol");
|
||||
|
||||
env.fund(XRP(10000), gw, alice, bob, carol);
|
||||
// fix1578 changes the return code. Verify expected behavior
|
||||
// without and with fix1578.
|
||||
for (auto const tweakedFeatures :
|
||||
{features - fix1578, features | fix1578})
|
||||
{
|
||||
Env env(*this, tweakedFeatures);
|
||||
|
||||
env.trust(alice["USD"](100), bob);
|
||||
env.trust(bob["USD"](100), carol);
|
||||
env.close();
|
||||
env.fund(XRP(10000), gw, alice, bob, carol);
|
||||
|
||||
env(pay(alice, carol, carol["USD"](50)), path(bob));
|
||||
env.trust(alice["USD"](100), bob);
|
||||
env.trust(bob["USD"](100), carol);
|
||||
env.close();
|
||||
|
||||
env(trust(alice, bob["USD"](100), bob, tfSetNoRipple));
|
||||
env(trust(bob, carol["USD"](100), carol, tfSetNoRipple));
|
||||
env.close();
|
||||
// After this payment alice has a -50 USD balance with bob, and
|
||||
// bob has a -50 USD balance with carol. So neither alice nor
|
||||
// bob should be able to clear the noRipple flag.
|
||||
env(pay(alice, carol, carol["USD"](50)), path(bob));
|
||||
env.close();
|
||||
|
||||
Json::Value params;
|
||||
params[jss::source_account] = alice.human();
|
||||
params[jss::destination_account] = carol.human();
|
||||
params[jss::destination_amount] = [] {
|
||||
Json::Value dest_amt;
|
||||
dest_amt[jss::currency] = "USD";
|
||||
dest_amt[jss::value] = "1";
|
||||
dest_amt[jss::issuer] = Account("carol").human();
|
||||
return dest_amt;
|
||||
}();
|
||||
TER const terNeg {tweakedFeatures[fix1578] ?
|
||||
TER {tecNO_PERMISSION} : TER {tesSUCCESS}};
|
||||
|
||||
auto const resp = env.rpc("json", "ripple_path_find", to_string(params));
|
||||
BEAST_EXPECT(resp[jss::result][jss::alternatives].size()==1);
|
||||
env(trust(
|
||||
alice, bob["USD"](100), bob, tfSetNoRipple), ter(terNeg));
|
||||
env(trust(
|
||||
bob, carol["USD"](100), carol, tfSetNoRipple), ter(terNeg));
|
||||
env.close();
|
||||
|
||||
Json::Value account_alice;
|
||||
account_alice[jss::account] = alice.human();
|
||||
auto const res = env.rpc("json", "account_lines", to_string(account_alice));
|
||||
auto const& lines = res[jss::result][jss::lines];
|
||||
BEAST_EXPECT(lines.size() == 1);
|
||||
BEAST_EXPECT(!lines[0u].isMember(jss::no_ripple));
|
||||
Json::Value params;
|
||||
params[jss::source_account] = alice.human();
|
||||
params[jss::destination_account] = carol.human();
|
||||
params[jss::destination_amount] = [] {
|
||||
Json::Value dest_amt;
|
||||
dest_amt[jss::currency] = "USD";
|
||||
dest_amt[jss::value] = "1";
|
||||
dest_amt[jss::issuer] = Account("carol").human();
|
||||
return dest_amt;
|
||||
}();
|
||||
|
||||
auto const resp = env.rpc(
|
||||
"json", "ripple_path_find", to_string(params));
|
||||
BEAST_EXPECT(resp[jss::result][jss::alternatives].size()==1);
|
||||
|
||||
auto getAccountLines = [&env] (Account const& acct)
|
||||
{
|
||||
Json::Value jv;
|
||||
jv[jss::account] = acct.human();
|
||||
auto const resp =
|
||||
env.rpc("json", "account_lines", to_string(jv));
|
||||
return resp[jss::result][jss::lines];
|
||||
};
|
||||
{
|
||||
auto const aliceLines = getAccountLines (alice);
|
||||
BEAST_EXPECT(aliceLines.size() == 1);
|
||||
BEAST_EXPECT(!aliceLines[0u].isMember(jss::no_ripple));
|
||||
|
||||
auto const bobLines = getAccountLines (bob);
|
||||
BEAST_EXPECT(bobLines.size() == 2);
|
||||
BEAST_EXPECT(!bobLines[0u].isMember(jss::no_ripple));
|
||||
BEAST_EXPECT(!bobLines[1u].isMember(jss::no_ripple));
|
||||
}
|
||||
|
||||
// Now carol sends the 50 USD back to alice. Then alice and
|
||||
// bob can set the noRipple flag.
|
||||
env(pay(carol, alice, alice["USD"](50)), path(bob));
|
||||
env.close();
|
||||
|
||||
env(trust(alice, bob["USD"](100), bob, tfSetNoRipple));
|
||||
env(trust(bob, carol["USD"](100), carol, tfSetNoRipple));
|
||||
env.close();
|
||||
{
|
||||
auto const aliceLines = getAccountLines (alice);
|
||||
BEAST_EXPECT(aliceLines.size() == 1);
|
||||
BEAST_EXPECT(aliceLines[0u].isMember(jss::no_ripple));
|
||||
|
||||
auto const bobLines = getAccountLines (bob);
|
||||
BEAST_EXPECT(bobLines.size() == 2);
|
||||
BEAST_EXPECT(bobLines[0u].isMember(jss::no_ripple_peer));
|
||||
BEAST_EXPECT(bobLines[1u].isMember(jss::no_ripple));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void testPairwise(FeatureBitset features)
|
||||
@@ -144,7 +192,8 @@ public:
|
||||
return dest_amt;
|
||||
}();
|
||||
|
||||
auto const resp = env.rpc("json", "ripple_path_find", to_string(params));
|
||||
Json::Value const resp {
|
||||
env.rpc("json", "ripple_path_find", to_string(params))};
|
||||
BEAST_EXPECT(resp[jss::result][jss::alternatives].size() == 0);
|
||||
|
||||
env(pay(alice, carol, bob["USD"](50)), ter(tecPATH_DRY));
|
||||
|
||||
Reference in New Issue
Block a user