Simplify fee handling during transaction submission:

Avoid custom overflow code; simply use 128-bit math to
maintain precision and return a saturated 64-bit value
as the final result.

Disallow use of negative values in the `fee_mult_max`
and `fee_div_max` fields. This change could potentially
cause submissions with negative values that would have
previously succeeded to now fail.
This commit is contained in:
Nik Bougalis
2017-01-18 03:33:46 -08:00
parent c7de7950c4
commit 8345475bc3
8 changed files with 135 additions and 106 deletions

View File

@@ -42,16 +42,8 @@ public:
return f;
}();
BEAST_EXPECT (scaleFeeBase (10000, fees) == 10000);
BEAST_EXPECT (scaleFeeLoad (10000, l, fees, false) == 10000);
BEAST_EXPECT (scaleFeeBase (1, fees) == 1);
BEAST_EXPECT (scaleFeeLoad (1, l, fees, false) == 1);
// Check new default fee values give same fees as old defaults
BEAST_EXPECT (scaleFeeBase (d.FEE_DEFAULT, fees) == 10);
BEAST_EXPECT (scaleFeeBase (d.FEE_ACCOUNT_RESERVE, fees) == 200 * SYSTEM_CURRENCY_PARTS);
BEAST_EXPECT (scaleFeeBase (d.FEE_OWNER_RESERVE, fees) == 50 * SYSTEM_CURRENCY_PARTS);
BEAST_EXPECT (scaleFeeBase (d.FEE_OFFER, fees) == 10);
}
};

View File

@@ -47,24 +47,12 @@ struct mulDiv_test : beast::unit_test::suite
BEAST_EXPECT(result.first && result.second == 1000000);
result = mulDiv(max, 1000, max / 1001);
BEAST_EXPECT(result.first && result.second == 1001000);
// 2^64 / 5 = 3689348814741910323, but we lose some precision
// starting in the 10th digit to avoid the overflow.
result = mulDiv(max32 + 1, max32 + 1, 5);
BEAST_EXPECT(result.first && result.second == 3689348813882916864);
BEAST_EXPECT(result.first && result.second == 3689348814741910323);
// Overflow
result = mulDiv(max - 1, max - 2, 5);
BEAST_EXPECT(!result.first && result.second == max);
try
{
mulDivThrow(max - 1, max - 2, 5);
fail();
}
catch (std::overflow_error const& e)
{
BEAST_EXPECT(e.what() == std::string("mulDiv"));
}
}
};

View File

@@ -232,8 +232,8 @@ R"({
}
})",
{
"Invalid field 'fee_mult_max', not an integer.",
"Invalid field 'fee_mult_max', not an integer.",
"Invalid field 'fee_mult_max', not a positive integer.",
"Invalid field 'fee_mult_max', not a positive integer.",
"Missing field 'tx_json.Fee'.",
"Missing field 'tx_json.SigningPubKey'."}},
@@ -253,8 +253,8 @@ R"({
}
})",
{
"Invalid field 'fee_div_max', not an integer.",
"Invalid field 'fee_div_max', not an integer.",
"Invalid field 'fee_div_max', not a positive integer.",
"Invalid field 'fee_div_max', not a positive integer.",
"Missing field 'tx_json.Fee'.",
"Missing field 'tx_json.SigningPubKey'."}},
@@ -315,8 +315,8 @@ R"({
}
})",
{
"Invalid field 'fee_div_max', not non-zero.",
"Invalid field 'fee_div_max', not non-zero.",
"Invalid field 'fee_div_max', not a positive integer.",
"Invalid field 'fee_div_max', not a positive integer.",
"Missing field 'tx_json.Fee'.",
"Missing field 'tx_json.SigningPubKey'."}},
@@ -2111,6 +2111,55 @@ public:
req[jss::tx_json][jss::Fee] == 3333);
}
{
// 9: negative mult
Json::Value req;
Json::Reader().parse(R"({
"fee_mult_max" : -5,
"x_queue_okay" : true,
"tx_json" : { }
})", req);
Json::Value result =
checkFee(req, Role::ADMIN, true,
env.app().config(), feeTrack,
env.app().getTxQ(), env.current());
BEAST_EXPECT(RPC::contains_error(result));
}
{
// 9: negative div
Json::Value req;
Json::Reader().parse(R"({
"fee_div_max" : -2,
"x_queue_okay" : true,
"tx_json" : { }
})", req);
Json::Value result =
checkFee(req, Role::ADMIN, true,
env.app().config(), feeTrack,
env.app().getTxQ(), env.current());
BEAST_EXPECT(RPC::contains_error(result));
}
{
// 9: negative mult & div
Json::Value req;
Json::Reader().parse(R"({
"fee_mult_max" : -2,
"fee_div_max" : -3,
"x_queue_okay" : true,
"tx_json" : { }
})", req);
Json::Value result =
checkFee(req, Role::ADMIN, true,
env.app().config(), feeTrack,
env.app().getTxQ(), env.current());
BEAST_EXPECT(RPC::contains_error(result));
}
}
// A function that can be called as though it would process a transaction.
@@ -2219,8 +2268,7 @@ public:
if (RPC::contains_error (result))
errStr = result["error_message"].asString ();
std::string const expStr (txnTest.expMsg[get<3>(testFunc)]);
BEAST_EXPECT(errStr == expStr);
BEAST_EXPECT(errStr == txnTest.expMsg[get<3>(testFunc)]);
}
}
}