Fix V2 line-quality bugs

This commit is contained in:
seelabs
2016-06-14 09:08:47 -04:00
committed by Miguel Portilla
parent 0952ebfc1d
commit da18f7c053
3 changed files with 132 additions and 22 deletions

View File

@@ -39,6 +39,7 @@ class DirectStepI : public StepImp<IOUAmount, IOUAmount, DirectStepI>
AccountID src_; AccountID src_;
AccountID dst_; AccountID dst_;
Currency currency_; Currency currency_;
bool isLast_ = false;
// Charge transfer fees when the prev step redeems // Charge transfer fees when the prev step redeems
Step const* const prevStep_ = nullptr; Step const* const prevStep_ = nullptr;
@@ -72,18 +73,22 @@ class DirectStepI : public StepImp<IOUAmount, IOUAmount, DirectStepI>
PaymentSandbox& sb, PaymentSandbox& sb,
bool srcRedeems, bool srcRedeems,
bool fwd) const; bool fwd) const;
public: public:
DirectStepI ( DirectStepI (
AccountID const& src, AccountID const& src,
AccountID const& dst, AccountID const& dst,
Currency const& c, Currency const& c,
Step const* prevStep, Step const* prevStep,
bool isLast,
beast::Journal j) beast::Journal j)
:src_(src) :src_(src)
, dst_(dst) , dst_(dst)
, currency_ (c) , currency_ (c)
, isLast_ (isLast)
, prevStep_ (prevStep) , prevStep_ (prevStep)
, j_ (j) {} , j_ (j)
{}
AccountID const& src () const AccountID const& src () const
{ {
@@ -122,6 +127,9 @@ class DirectStepI : public StepImp<IOUAmount, IOUAmount, DirectStepI>
bool bool
redeems (ReadView const& sb, bool fwd) const override; redeems (ReadView const& sb, bool fwd) const override;
std::uint32_t
lineQualityIn (ReadView const& v) const override;
std::pair<IOUAmount, IOUAmount> std::pair<IOUAmount, IOUAmount>
revImp ( revImp (
PaymentSandbox& sb, PaymentSandbox& sb,
@@ -484,11 +492,11 @@ DirectStepI::validFwd (
static static
std::uint32_t std::uint32_t
quality ( quality (
PaymentSandbox const& sb, ReadView const& sb,
AccountID const& src, AccountID const& src,
AccountID const& dst, AccountID const& dst,
Currency const& currency, Currency const& currency,
// set true for quality in, false for quality out // set true for dst quality in, false for src quality out
bool qin) bool qin)
{ {
if (src == dst) if (src == dst)
@@ -501,18 +509,20 @@ quality (
return QUALITY_ONE; return QUALITY_ONE;
auto const& field = [&]() -> SF_U32 const& auto const& field = [&]() -> SF_U32 const&
{
if (dst < src)
{ {
if (qin) if (qin)
{
// compute dst quality in
if (dst < src)
return sfLowQualityIn; return sfLowQualityIn;
else else
return sfLowQualityOut; return sfHighQualityIn;
} }
else else
{ {
if (qin) // compute src quality out
return sfHighQualityIn; if (src < dst)
return sfLowQualityOut;
else else
return sfHighQualityOut; return sfHighQualityOut;
} }
@@ -536,27 +546,35 @@ DirectStepI::qualities (
{ {
if (srcRedeems) if (srcRedeems)
{ {
return std::make_pair( if (!prevStep_)
quality ( return {QUALITY_ONE, QUALITY_ONE};
sb, src_, dst_, currency_,
false), auto const prevStepQIn = prevStep_->lineQualityIn (sb);
QUALITY_ONE); auto srcQOut = quality (sb, src_, dst_, currency_, false);
if (prevStepQIn > srcQOut)
srcQOut = prevStepQIn;
return {srcQOut, QUALITY_ONE};
} }
else else
{ {
// Charge a transfer rate when issuing and previous step redeems // Charge a transfer rate when issuing and previous step redeems
auto const prevStepRedeems = prevStep_ && prevStep_->redeems (sb, fwd); auto const prevStepRedeems = prevStep_ && prevStep_->redeems (sb, fwd);
std::uint32_t const srcQOut = prevStepRedeems std::uint32_t const srcQOut =
? transferRate (sb, src_).value prevStepRedeems ? transferRate (sb, src_).value : QUALITY_ONE;
: QUALITY_ONE; auto dstQIn = quality (sb, src_, dst_, currency_, true);
return std::make_pair( if (isLast_ && dstQIn > QUALITY_ONE)
srcQOut, dstQIn = QUALITY_ONE;
quality ( // dst quality in return {srcQOut, dstQIn};
sb, src_, dst_, currency_,
true));
} }
} }
std::uint32_t
DirectStepI::lineQualityIn (ReadView const& v) const
{
// dst quality in
return quality (v, src_, dst_, currency_, true);
}
TER DirectStepI::check (StrandContext const& ctx) const TER DirectStepI::check (StrandContext const& ctx) const
{ {
if (!src_ || !dst_) if (!src_ || !dst_)
@@ -565,6 +583,12 @@ TER DirectStepI::check (StrandContext const& ctx) const
return temBAD_PATH; return temBAD_PATH;
} }
if (src_ == dst_)
{
JLOG (j_.debug()) << "DirectStepI: same src and dst.";
return temBAD_PATH;
}
{ {
auto sleSrc = ctx.view.read (keylet::account (src_)); auto sleSrc = ctx.view.read (keylet::account (src_));
if (!sleSrc) if (!sleSrc)
@@ -692,7 +716,7 @@ make_DirectStepI (
{ {
// Only charge a transfer fee if the previous step redeems // Only charge a transfer fee if the previous step redeems
auto r = std::make_unique<DirectStepI> ( auto r = std::make_unique<DirectStepI> (
src, dst, c, ctx.prevStep, ctx.j); src, dst, c, ctx.prevStep, ctx.isLast, ctx.j);
auto ter = r->check (ctx); auto ter = r->check (ctx);
if (ter != tesSUCCESS) if (ter != tesSUCCESS)
return {ter, nullptr}; return {ter, nullptr};

View File

@@ -22,6 +22,7 @@
#include <ripple/app/paths/impl/AmountSpec.h> #include <ripple/app/paths/impl/AmountSpec.h>
#include <ripple/basics/Log.h> #include <ripple/basics/Log.h>
#include <ripple/protocol/Quality.h>
#include <ripple/protocol/STLedgerEntry.h> #include <ripple/protocol/STLedgerEntry.h>
#include <ripple/protocol/TER.h> #include <ripple/protocol/TER.h>
@@ -132,6 +133,14 @@ public:
return false; return false;
} }
/** If this step is a DirectStepI, return the quality in of the dst account.
*/
virtual std::uint32_t
lineQualityIn (ReadView const&) const
{
return QUALITY_ONE;
}
/** /**
If this step is a BookStep, return the book. If this step is a BookStep, return the book.
*/ */

View File

@@ -512,6 +512,82 @@ struct Flow_test : public beast::unit_test::suite
} }
} }
void testLineQuality ()
{
testcase ("Line Quality");
using namespace jtx;
auto const alice = Account ("alice");
auto const bob = Account ("bob");
auto const carol = Account ("carol");
auto const dan = Account ("dan");
auto const USDA = alice["USD"];
auto const USDB = bob["USD"];
auto const USDC = carol["USD"];
auto const USDD = dan["USD"];
// Dan -> Bob -> Alice -> Carol; vary bobDanQIn and bobAliceQOut
for (auto bobDanQIn : {80, 100, 120})
for (auto bobAliceQOut : {80, 100, 120})
for (auto const& f : {feature ("nullFeature"), featureFlowV2})
{
if (f != featureFlowV2 && bobDanQIn < 100 && bobAliceQOut < 100)
continue; // Bug in flow v1
Env env (*this, features (f));
env.fund (XRP (10000), alice, bob, carol, dan);
env (trust (bob, USDD (100)), qualityInPercent (bobDanQIn));
env (trust (bob, USDA (100)),
qualityOutPercent (bobAliceQOut));
env (trust (carol, USDA (100)));
env (pay (alice, bob, USDA (100)));
env.require (balance (bob, USDA (100)));
env (pay (dan, carol, USDA (10)), path (bob),
sendmax (USDD (100)), txflags (tfNoRippleDirect));
env.require (balance (bob, USDA (90)));
if (bobAliceQOut > bobDanQIn)
env.require (
balance (bob, USDD (10.0 * double(bobAliceQOut) /
double(bobDanQIn))));
else
env.require (balance (bob, USDD (10)));
env.require (balance (carol, USDA (10)));
}
// bob -> alice -> carol; vary carolAliceQIn
for (auto carolAliceQIn : {80, 100, 120})
for (auto const& f : {feature ("nullFeature"), featureFlowV2})
{
Env env (*this, features (f));
env.fund (XRP (10000), alice, bob, carol);
env (trust (bob, USDA (10)));
env (trust (carol, USDA (10)), qualityInPercent (carolAliceQIn));
env (pay (alice, bob, USDA (10)));
env.require (balance (bob, USDA (10)));
env (pay (bob, carol, USDA (5)), sendmax (USDA (10)));
auto const effectiveQ =
carolAliceQIn > 100 ? 1.0 : carolAliceQIn / 100.0;
env.require (balance (bob, USDA (10.0 - 5.0 / effectiveQ)));
}
// bob -> alice -> carol; bobAliceQOut varies.
for (auto bobAliceQOut : {80, 100, 120})
for (auto const& f : {feature ("nullFeature"), featureFlowV2})
{
Env env (*this, features (f));
env.fund (XRP (10000), alice, bob, carol);
env (trust (bob, USDA (10)), qualityOutPercent (bobAliceQOut));
env (trust (carol, USDA (10)));
env (pay (alice, bob, USDA (10)));
env.require (balance (bob, USDA (10)));
env (pay (bob, carol, USDA (5)), sendmax (USDA (5)));
env.require (balance (carol, USDA (5)));
env.require (balance (bob, USDA (10-5)));
}
}
void testBookStep () void testBookStep ()
{ {
testcase ("Book Step"); testcase ("Book Step");
@@ -1185,6 +1261,7 @@ struct Flow_test : public beast::unit_test::suite
void run() override void run() override
{ {
testDirectStep (); testDirectStep ();
testLineQuality();
testBookStep (); testBookStep ();
testTransferRate (); testTransferRate ();
testToStrand (); testToStrand ();