fix(gateway_balances): handle overflow exception: (#4355)

* Prevent internal error by catching overflow exception in `gateway_balances`.
* Treat `gateway_balances` obligations overflow as max (largest valid) `STAmount`.
  * Note that very large sums of STAmount are approximations regardless.

---------

Co-authored-by: Scott Schurr <scott@ripple.com>
This commit is contained in:
RichardAH
2023-03-16 18:25:40 +01:00
committed by GitHub
parent 0f1ffff068
commit 10555faa92
2 changed files with 73 additions and 1 deletions

View File

@@ -184,7 +184,23 @@ doGatewayBalances(RPC::JsonContext& context)
bal = -rs->getBalance();
}
else
bal -= rs->getBalance();
{
try
{
bal -= rs->getBalance();
}
catch (std::runtime_error const&)
{
// Presumably the exception was caused by overflow.
// On overflow return the largest valid STAmount.
// Very large sums of STAmount are approximations
// anyway.
bal = STAmount(
bal.issue(),
STAmount::cMaxValue,
STAmount::cMaxOffset);
}
}
}
});
}

View File

@@ -148,6 +148,60 @@ public:
}
}
void
testGWBOverflow()
{
using namespace std::chrono_literals;
using namespace jtx;
Env env(*this);
// Gateway account and assets
Account const alice{"alice"};
env.fund(XRP(10000), alice);
env.close();
auto USD = alice["USD"];
// The largest valid STAmount of USD:
STAmount const maxUSD(
USD.issue(), STAmount::cMaxValue, STAmount::cMaxOffset);
// Create a hotwallet
Account const hw{"hw"};
env.fund(XRP(10000), hw);
env(trust(hw, maxUSD));
env.close();
env(pay(alice, hw, maxUSD));
// Create some clients
Account const bob{"bob"};
env.fund(XRP(10000), bob);
env(trust(bob, maxUSD));
env.close();
env(pay(alice, bob, maxUSD));
Account const charley{"charley"};
env.fund(XRP(10000), charley);
env(trust(charley, maxUSD));
env.close();
env(pay(alice, charley, maxUSD));
env.close();
auto wsc = makeWSClient(env.app().config());
Json::Value query;
query[jss::account] = alice.human();
query[jss::hotwallet] = hw.human();
// Note that the sum of bob's and charley's USD balances exceeds
// the amount that can be represented in an STAmount. Nevertheless
// we get a valid "obligations" that shows the maximum valid
// STAmount.
auto jv = wsc->invoke("gateway_balances", query);
expect(jv[jss::status] == "success");
expect(jv[jss::result][jss::obligations]["USD"] == maxUSD.getText());
}
void
run() override
{
@@ -155,6 +209,8 @@ public:
auto const sa = supported_amendments();
testGWB(sa - featureFlowCross);
testGWB(sa);
testGWBOverflow();
}
};