From 0d0464fdb98952d7e5fbfbdc815e4ae996d6d02f Mon Sep 17 00:00:00 2001 From: Richard Holland Date: Wed, 30 Nov 2022 13:10:41 +0000 Subject: [PATCH 1/2] catch overflow exception in gateway_balances --- src/ripple/protocol/jss.h | 1 + src/ripple/rpc/handlers/GatewayBalances.cpp | 11 ++++++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/ripple/protocol/jss.h b/src/ripple/protocol/jss.h index 1c5bf8463b0..7bd3db3cbd1 100644 --- a/src/ripple/protocol/jss.h +++ b/src/ripple/protocol/jss.h @@ -438,6 +438,7 @@ JSS(open); // out: handlers/Ledger JSS(open_ledger_cost); // out: SubmitTransaction JSS(open_ledger_fee); // out: TxQ JSS(open_ledger_level); // out: TxQ +JSS(overflow); // out: gateway_balances JSS(owner); // in: LedgerEntry, out: NetworkOPs JSS(owner_funds); // in/out: Ledger, NetworkOPs, AcceptedLedgerTx JSS(page_index); diff --git a/src/ripple/rpc/handlers/GatewayBalances.cpp b/src/ripple/rpc/handlers/GatewayBalances.cpp index d0770f31edf..80aec9d4082 100644 --- a/src/ripple/rpc/handlers/GatewayBalances.cpp +++ b/src/ripple/rpc/handlers/GatewayBalances.cpp @@ -184,7 +184,16 @@ doGatewayBalances(RPC::JsonContext& context) bal = -rs->getBalance(); } else - bal -= rs->getBalance(); + { + try + { + bal -= rs->getBalance(); + } + catch (std::runtime_error& e) + { + result[jss::overflow] = "true"; + } + } } }); } From 36ffe0cd885c9caac7b0e4e38afad05d2421be49 Mon Sep 17 00:00:00 2001 From: Scott Schurr Date: Fri, 6 Jan 2023 16:39:49 -0800 Subject: [PATCH 2/2] [FOLD] Treat gateway_balances obligations overflow as max STAmount --- src/ripple/protocol/jss.h | 1 - src/ripple/rpc/handlers/GatewayBalances.cpp | 11 +++- src/test/rpc/GatewayBalances_test.cpp | 56 +++++++++++++++++++++ 3 files changed, 65 insertions(+), 3 deletions(-) diff --git a/src/ripple/protocol/jss.h b/src/ripple/protocol/jss.h index 7bd3db3cbd1..1c5bf8463b0 100644 --- a/src/ripple/protocol/jss.h +++ b/src/ripple/protocol/jss.h @@ -438,7 +438,6 @@ JSS(open); // out: handlers/Ledger JSS(open_ledger_cost); // out: SubmitTransaction JSS(open_ledger_fee); // out: TxQ JSS(open_ledger_level); // out: TxQ -JSS(overflow); // out: gateway_balances JSS(owner); // in: LedgerEntry, out: NetworkOPs JSS(owner_funds); // in/out: Ledger, NetworkOPs, AcceptedLedgerTx JSS(page_index); diff --git a/src/ripple/rpc/handlers/GatewayBalances.cpp b/src/ripple/rpc/handlers/GatewayBalances.cpp index 80aec9d4082..3a422c6e965 100644 --- a/src/ripple/rpc/handlers/GatewayBalances.cpp +++ b/src/ripple/rpc/handlers/GatewayBalances.cpp @@ -189,9 +189,16 @@ doGatewayBalances(RPC::JsonContext& context) { bal -= rs->getBalance(); } - catch (std::runtime_error& e) + catch (std::runtime_error const&) { - result[jss::overflow] = "true"; + // 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); } } } diff --git a/src/test/rpc/GatewayBalances_test.cpp b/src/test/rpc/GatewayBalances_test.cpp index 6b5dcdb8a0f..c14ec0f043c 100644 --- a/src/test/rpc/GatewayBalances_test.cpp +++ b/src/test/rpc/GatewayBalances_test.cpp @@ -148,6 +148,60 @@ class GatewayBalances_test : public beast::unit_test::suite } } + 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 @@ class GatewayBalances_test : public beast::unit_test::suite auto const sa = supported_amendments(); testGWB(sa - featureFlowCross); testGWB(sa); + + testGWBOverflow(); } };