mirror of
https://github.com/XRPLF/rippled.git
synced 2025-12-03 17:35:51 +00:00
Compile time check preflight returns no tec (RIPD-1624):
The six different ranges of TER codes are broken up into six different enumerations. A template class allows subsets of these enumerations to be aggregated. This technique allows verification at compile time that no TEC codes are returned before the signature is checked. Conversion between TER instance and integer is provided by named functions. This makes accidental conversion almost impossible and makes type abuse easier to spot in the code base.
This commit is contained in:
@@ -47,12 +47,12 @@ public:
|
|||||||
beast::Journal const j;
|
beast::Journal const j;
|
||||||
|
|
||||||
/// Intermediate transaction result
|
/// Intermediate transaction result
|
||||||
TER const ter;
|
NotTEC const ter;
|
||||||
|
|
||||||
/// Constructor
|
/// Constructor
|
||||||
template<class Context>
|
template<class Context>
|
||||||
PreflightResult(Context const& ctx_,
|
PreflightResult(Context const& ctx_,
|
||||||
TER ter_)
|
NotTEC ter_)
|
||||||
: tx(ctx_.tx)
|
: tx(ctx_.tx)
|
||||||
, rules(ctx_.rules)
|
, rules(ctx_.rules)
|
||||||
, flags(ctx_.flags)
|
, flags(ctx_.flags)
|
||||||
|
|||||||
@@ -104,8 +104,8 @@ ApplyContext::checkInvariantsHelper(TER terResult, std::index_sequence<Is...>)
|
|||||||
[](auto const& b) { return b; }))
|
[](auto const& b) { return b; }))
|
||||||
{
|
{
|
||||||
terResult = (terResult == tecINVARIANT_FAILED) ?
|
terResult = (terResult == tecINVARIANT_FAILED) ?
|
||||||
tefINVARIANT_FAILED :
|
TER {tefINVARIANT_FAILED} :
|
||||||
tecINVARIANT_FAILED ;
|
TER {tecINVARIANT_FAILED} ;
|
||||||
JLOG(journal.fatal()) <<
|
JLOG(journal.fatal()) <<
|
||||||
"Transaction has failed one or more invariants: " <<
|
"Transaction has failed one or more invariants: " <<
|
||||||
to_string(tx.getJson (0));
|
to_string(tx.getJson (0));
|
||||||
@@ -114,8 +114,8 @@ ApplyContext::checkInvariantsHelper(TER terResult, std::index_sequence<Is...>)
|
|||||||
catch(std::exception const& ex)
|
catch(std::exception const& ex)
|
||||||
{
|
{
|
||||||
terResult = (terResult == tecINVARIANT_FAILED) ?
|
terResult = (terResult == tecINVARIANT_FAILED) ?
|
||||||
tefINVARIANT_FAILED :
|
TER {tefINVARIANT_FAILED} :
|
||||||
tecINVARIANT_FAILED ;
|
TER {tecINVARIANT_FAILED} ;
|
||||||
JLOG(journal.fatal()) <<
|
JLOG(journal.fatal()) <<
|
||||||
"Transaction caused an exception in an invariant" <<
|
"Transaction caused an exception in an invariant" <<
|
||||||
", ex: " << ex.what() <<
|
", ex: " << ex.what() <<
|
||||||
|
|||||||
@@ -28,13 +28,13 @@
|
|||||||
|
|
||||||
namespace ripple {
|
namespace ripple {
|
||||||
|
|
||||||
TER
|
NotTEC
|
||||||
CancelCheck::preflight (PreflightContext const& ctx)
|
CancelCheck::preflight (PreflightContext const& ctx)
|
||||||
{
|
{
|
||||||
if (! ctx.rules.enabled (featureChecks))
|
if (! ctx.rules.enabled (featureChecks))
|
||||||
return temDISABLED;
|
return temDISABLED;
|
||||||
|
|
||||||
TER const ret {preflight1 (ctx)};
|
NotTEC const ret {preflight1 (ctx)};
|
||||||
if (! isTesSuccess (ret))
|
if (! isTesSuccess (ret))
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
TER
|
NotTEC
|
||||||
preflight (PreflightContext const& ctx);
|
preflight (PreflightContext const& ctx);
|
||||||
|
|
||||||
static
|
static
|
||||||
|
|||||||
@@ -24,7 +24,7 @@
|
|||||||
|
|
||||||
namespace ripple {
|
namespace ripple {
|
||||||
|
|
||||||
TER
|
NotTEC
|
||||||
CancelOffer::preflight (PreflightContext const& ctx)
|
CancelOffer::preflight (PreflightContext const& ctx)
|
||||||
{
|
{
|
||||||
auto const ret = preflight1 (ctx);
|
auto const ret = preflight1 (ctx);
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
TER
|
NotTEC
|
||||||
preflight (PreflightContext const& ctx);
|
preflight (PreflightContext const& ctx);
|
||||||
|
|
||||||
static
|
static
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
|
|
||||||
namespace ripple {
|
namespace ripple {
|
||||||
|
|
||||||
TER
|
NotTEC
|
||||||
CancelTicket::preflight (PreflightContext const& ctx)
|
CancelTicket::preflight (PreflightContext const& ctx)
|
||||||
{
|
{
|
||||||
if (! ctx.rules.enabled(featureTickets))
|
if (! ctx.rules.enabled(featureTickets))
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
TER
|
NotTEC
|
||||||
preflight (PreflightContext const& ctx);
|
preflight (PreflightContext const& ctx);
|
||||||
|
|
||||||
TER doApply () override;
|
TER doApply () override;
|
||||||
|
|||||||
@@ -31,13 +31,13 @@
|
|||||||
|
|
||||||
namespace ripple {
|
namespace ripple {
|
||||||
|
|
||||||
TER
|
NotTEC
|
||||||
CashCheck::preflight (PreflightContext const& ctx)
|
CashCheck::preflight (PreflightContext const& ctx)
|
||||||
{
|
{
|
||||||
if (! ctx.rules.enabled (featureChecks))
|
if (! ctx.rules.enabled (featureChecks))
|
||||||
return temDISABLED;
|
return temDISABLED;
|
||||||
|
|
||||||
TER const ret {preflight1 (ctx)};
|
NotTEC const ret {preflight1 (ctx)};
|
||||||
if (! isTesSuccess (ret))
|
if (! isTesSuccess (ret))
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
TER
|
NotTEC
|
||||||
preflight (PreflightContext const& ctx);
|
preflight (PreflightContext const& ctx);
|
||||||
|
|
||||||
static
|
static
|
||||||
|
|||||||
@@ -27,7 +27,7 @@
|
|||||||
|
|
||||||
namespace ripple {
|
namespace ripple {
|
||||||
|
|
||||||
TER
|
NotTEC
|
||||||
Change::preflight (PreflightContext const& ctx)
|
Change::preflight (PreflightContext const& ctx)
|
||||||
{
|
{
|
||||||
auto const ret = preflight0(ctx);
|
auto const ret = preflight0(ctx);
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
TER
|
NotTEC
|
||||||
preflight (PreflightContext const& ctx);
|
preflight (PreflightContext const& ctx);
|
||||||
|
|
||||||
TER doApply () override;
|
TER doApply () override;
|
||||||
|
|||||||
@@ -28,13 +28,13 @@
|
|||||||
|
|
||||||
namespace ripple {
|
namespace ripple {
|
||||||
|
|
||||||
TER
|
NotTEC
|
||||||
CreateCheck::preflight (PreflightContext const& ctx)
|
CreateCheck::preflight (PreflightContext const& ctx)
|
||||||
{
|
{
|
||||||
if (! ctx.rules.enabled (featureChecks))
|
if (! ctx.rules.enabled (featureChecks))
|
||||||
return temDISABLED;
|
return temDISABLED;
|
||||||
|
|
||||||
TER const ret {preflight1 (ctx)};
|
NotTEC const ret {preflight1 (ctx)};
|
||||||
if (! isTesSuccess (ret))
|
if (! isTesSuccess (ret))
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
TER
|
NotTEC
|
||||||
preflight (PreflightContext const& ctx);
|
preflight (PreflightContext const& ctx);
|
||||||
|
|
||||||
static
|
static
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ CreateOffer::calculateMaxSpend(STTx const& tx)
|
|||||||
saTakerGets.xrp() : beast::zero;
|
saTakerGets.xrp() : beast::zero;
|
||||||
}
|
}
|
||||||
|
|
||||||
TER
|
NotTEC
|
||||||
CreateOffer::preflight (PreflightContext const& ctx)
|
CreateOffer::preflight (PreflightContext const& ctx)
|
||||||
{
|
{
|
||||||
auto const ret = preflight1 (ctx);
|
auto const ret = preflight1 (ctx);
|
||||||
@@ -198,7 +198,9 @@ CreateOffer::preclaim(PreclaimContext const& ctx)
|
|||||||
//
|
//
|
||||||
// The return code change is attached to featureChecks as a convenience.
|
// The return code change is attached to featureChecks as a convenience.
|
||||||
// The change is not big enough to deserve its own amendment.
|
// The change is not big enough to deserve its own amendment.
|
||||||
return ctx.view.rules().enabled(featureChecks) ? tecEXPIRED : tesSUCCESS;
|
return ctx.view.rules().enabled(featureChecks)
|
||||||
|
? TER {tecEXPIRED}
|
||||||
|
: TER {tesSUCCESS};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure that we are authorized to hold what the taker will pay us.
|
// Make sure that we are authorized to hold what the taker will pay us.
|
||||||
@@ -231,8 +233,8 @@ CreateOffer::checkAcceptAsset(ReadView const& view,
|
|||||||
to_string (issue.account);
|
to_string (issue.account);
|
||||||
|
|
||||||
return (flags & tapRETRY)
|
return (flags & tapRETRY)
|
||||||
? terNO_ACCOUNT
|
? TER {terNO_ACCOUNT}
|
||||||
: tecNO_ISSUER;
|
: TER {tecNO_ISSUER};
|
||||||
}
|
}
|
||||||
|
|
||||||
// This code is attached to the FlowCross amendment as a matter of
|
// This code is attached to the FlowCross amendment as a matter of
|
||||||
@@ -250,8 +252,8 @@ CreateOffer::checkAcceptAsset(ReadView const& view,
|
|||||||
if (!trustLine)
|
if (!trustLine)
|
||||||
{
|
{
|
||||||
return (flags & tapRETRY)
|
return (flags & tapRETRY)
|
||||||
? terNO_LINE
|
? TER {terNO_LINE}
|
||||||
: tecNO_LINE;
|
: TER {tecNO_LINE};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Entries have a canonical representation, determined by a
|
// Entries have a canonical representation, determined by a
|
||||||
@@ -268,8 +270,8 @@ CreateOffer::checkAcceptAsset(ReadView const& view,
|
|||||||
"delay: can't receive IOUs from issuer without auth.";
|
"delay: can't receive IOUs from issuer without auth.";
|
||||||
|
|
||||||
return (flags & tapRETRY)
|
return (flags & tapRETRY)
|
||||||
? terNO_AUTH
|
? TER {terNO_AUTH}
|
||||||
: tecNO_AUTH;
|
: TER {tecNO_AUTH};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1073,7 +1075,7 @@ CreateOffer::applyGuts (Sandbox& sb, Sandbox& sbCancel)
|
|||||||
|
|
||||||
auto viewJ = ctx_.app.journal("View");
|
auto viewJ = ctx_.app.journal("View");
|
||||||
|
|
||||||
auto result = tesSUCCESS;
|
TER result = tesSUCCESS;
|
||||||
|
|
||||||
// Process a cancellation request that's passed along with an offer.
|
// Process a cancellation request that's passed along with an offer.
|
||||||
if (cancelSequence)
|
if (cancelSequence)
|
||||||
@@ -1107,7 +1109,7 @@ CreateOffer::applyGuts (Sandbox& sb, Sandbox& sbCancel)
|
|||||||
// The return code change is attached to featureChecks as a convenience.
|
// The return code change is attached to featureChecks as a convenience.
|
||||||
// The change is not big enough to deserve its own amendment.
|
// The change is not big enough to deserve its own amendment.
|
||||||
TER const ter {ctx_.view().rules().enabled(
|
TER const ter {ctx_.view().rules().enabled(
|
||||||
featureChecks) ? tecEXPIRED : tesSUCCESS};
|
featureChecks) ? TER {tecEXPIRED} : TER {tesSUCCESS}};
|
||||||
return{ ter, true };
|
return{ ter, true };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ public:
|
|||||||
|
|
||||||
/** Enforce constraints beyond those of the Transactor base class. */
|
/** Enforce constraints beyond those of the Transactor base class. */
|
||||||
static
|
static
|
||||||
TER
|
NotTEC
|
||||||
preflight (PreflightContext const& ctx);
|
preflight (PreflightContext const& ctx);
|
||||||
|
|
||||||
/** Enforce constraints beyond those of the Transactor base class. */
|
/** Enforce constraints beyond those of the Transactor base class. */
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
|
|
||||||
namespace ripple {
|
namespace ripple {
|
||||||
|
|
||||||
TER
|
NotTEC
|
||||||
CreateTicket::preflight (PreflightContext const& ctx)
|
CreateTicket::preflight (PreflightContext const& ctx)
|
||||||
{
|
{
|
||||||
if (! ctx.rules.enabled(featureTickets))
|
if (! ctx.rules.enabled(featureTickets))
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
TER
|
NotTEC
|
||||||
preflight (PreflightContext const& ctx);
|
preflight (PreflightContext const& ctx);
|
||||||
|
|
||||||
TER doApply () override;
|
TER doApply () override;
|
||||||
|
|||||||
@@ -92,7 +92,7 @@ EscrowCreate::calculateMaxSpend(STTx const& tx)
|
|||||||
return tx[sfAmount].xrp();
|
return tx[sfAmount].xrp();
|
||||||
}
|
}
|
||||||
|
|
||||||
TER
|
NotTEC
|
||||||
EscrowCreate::preflight (PreflightContext const& ctx)
|
EscrowCreate::preflight (PreflightContext const& ctx)
|
||||||
{
|
{
|
||||||
if (! ctx.rules.enabled(featureEscrow))
|
if (! ctx.rules.enabled(featureEscrow))
|
||||||
@@ -293,7 +293,7 @@ checkCondition (Slice f, Slice c)
|
|||||||
return validate (*fulfillment, *condition);
|
return validate (*fulfillment, *condition);
|
||||||
}
|
}
|
||||||
|
|
||||||
TER
|
NotTEC
|
||||||
EscrowFinish::preflight (PreflightContext const& ctx)
|
EscrowFinish::preflight (PreflightContext const& ctx)
|
||||||
{
|
{
|
||||||
if (! ctx.rules.enabled(featureEscrow))
|
if (! ctx.rules.enabled(featureEscrow))
|
||||||
@@ -503,7 +503,7 @@ EscrowFinish::doApply()
|
|||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
TER
|
NotTEC
|
||||||
EscrowCancel::preflight (PreflightContext const& ctx)
|
EscrowCancel::preflight (PreflightContext const& ctx)
|
||||||
{
|
{
|
||||||
if (! ctx.rules.enabled(featureEscrow))
|
if (! ctx.rules.enabled(featureEscrow))
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ public:
|
|||||||
calculateMaxSpend(STTx const& tx);
|
calculateMaxSpend(STTx const& tx);
|
||||||
|
|
||||||
static
|
static
|
||||||
TER
|
NotTEC
|
||||||
preflight (PreflightContext const& ctx);
|
preflight (PreflightContext const& ctx);
|
||||||
|
|
||||||
TER
|
TER
|
||||||
@@ -59,7 +59,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
TER
|
NotTEC
|
||||||
preflight (PreflightContext const& ctx);
|
preflight (PreflightContext const& ctx);
|
||||||
|
|
||||||
static
|
static
|
||||||
@@ -83,7 +83,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
TER
|
NotTEC
|
||||||
preflight (PreflightContext const& ctx);
|
preflight (PreflightContext const& ctx);
|
||||||
|
|
||||||
TER
|
TER
|
||||||
|
|||||||
@@ -154,7 +154,7 @@ closeChannel (
|
|||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
TER
|
NotTEC
|
||||||
PayChanCreate::preflight (PreflightContext const& ctx)
|
PayChanCreate::preflight (PreflightContext const& ctx)
|
||||||
{
|
{
|
||||||
if (!ctx.rules.enabled (featurePayChan))
|
if (!ctx.rules.enabled (featurePayChan))
|
||||||
@@ -262,7 +262,7 @@ PayChanCreate::doApply()
|
|||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
TER
|
NotTEC
|
||||||
PayChanFund::preflight (PreflightContext const& ctx)
|
PayChanFund::preflight (PreflightContext const& ctx)
|
||||||
{
|
{
|
||||||
if (!ctx.rules.enabled (featurePayChan))
|
if (!ctx.rules.enabled (featurePayChan))
|
||||||
@@ -347,13 +347,17 @@ PayChanFund::doApply()
|
|||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
TER
|
NotTEC
|
||||||
PayChanClaim::preflight (PreflightContext const& ctx)
|
PayChanClaim::preflight (PreflightContext const& ctx)
|
||||||
{
|
{
|
||||||
if (! ctx.rules.enabled(featurePayChan))
|
if (! ctx.rules.enabled(featurePayChan))
|
||||||
return temDISABLED;
|
return temDISABLED;
|
||||||
|
|
||||||
bool const noTecs = ctx.rules.enabled(fix1512);
|
// A search through historic MainNet ledgers by the data team found no
|
||||||
|
// occurrences of a transaction with the error that fix1512 fixed. That
|
||||||
|
// means there are no old transactions with that error that we might
|
||||||
|
// need to replay. So the check for fix1512 is removed. Apr 2018.
|
||||||
|
// bool const noTecs = ctx.rules.enabled(fix1512);
|
||||||
|
|
||||||
auto const ret = preflight1 (ctx);
|
auto const ret = preflight1 (ctx);
|
||||||
if (!isTesSuccess (ret))
|
if (!isTesSuccess (ret))
|
||||||
@@ -368,12 +372,7 @@ PayChanClaim::preflight (PreflightContext const& ctx)
|
|||||||
return temBAD_AMOUNT;
|
return temBAD_AMOUNT;
|
||||||
|
|
||||||
if (bal && amt && *bal > *amt)
|
if (bal && amt && *bal > *amt)
|
||||||
{
|
return temBAD_AMOUNT;
|
||||||
if (noTecs)
|
|
||||||
return temBAD_AMOUNT;
|
|
||||||
else
|
|
||||||
return tecNO_PERMISSION;
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
{
|
||||||
auto const flags = ctx.tx.getFlags();
|
auto const flags = ctx.tx.getFlags();
|
||||||
@@ -398,12 +397,7 @@ PayChanClaim::preflight (PreflightContext const& ctx)
|
|||||||
auto const authAmt = amt ? amt->xrp() : reqBalance;
|
auto const authAmt = amt ? amt->xrp() : reqBalance;
|
||||||
|
|
||||||
if (reqBalance > authAmt)
|
if (reqBalance > authAmt)
|
||||||
{
|
return temBAD_AMOUNT;
|
||||||
if (noTecs)
|
|
||||||
return temBAD_AMOUNT;
|
|
||||||
else
|
|
||||||
return tecNO_PERMISSION;
|
|
||||||
}
|
|
||||||
|
|
||||||
Keylet const k (ltPAYCHAN, ctx.tx[sfPayChannel]);
|
Keylet const k (ltPAYCHAN, ctx.tx[sfPayChannel]);
|
||||||
if (!publicKeyType(ctx.tx[sfPublicKey]))
|
if (!publicKeyType(ctx.tx[sfPublicKey]))
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
TER
|
NotTEC
|
||||||
preflight (PreflightContext const& ctx);
|
preflight (PreflightContext const& ctx);
|
||||||
|
|
||||||
static
|
static
|
||||||
@@ -59,7 +59,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
TER
|
NotTEC
|
||||||
preflight (PreflightContext const& ctx);
|
preflight (PreflightContext const& ctx);
|
||||||
|
|
||||||
TER
|
TER
|
||||||
@@ -79,7 +79,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
TER
|
NotTEC
|
||||||
preflight (PreflightContext const& ctx);
|
preflight (PreflightContext const& ctx);
|
||||||
|
|
||||||
TER
|
TER
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ Payment::calculateMaxSpend(STTx const& tx)
|
|||||||
return saDstAmount.native() ? saDstAmount.xrp() : beast::zero;
|
return saDstAmount.native() ? saDstAmount.xrp() : beast::zero;
|
||||||
}
|
}
|
||||||
|
|
||||||
TER
|
NotTEC
|
||||||
Payment::preflight (PreflightContext const& ctx)
|
Payment::preflight (PreflightContext const& ctx)
|
||||||
{
|
{
|
||||||
auto const ret = preflight1 (ctx);
|
auto const ret = preflight1 (ctx);
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ public:
|
|||||||
calculateMaxSpend(STTx const& tx);
|
calculateMaxSpend(STTx const& tx);
|
||||||
|
|
||||||
static
|
static
|
||||||
TER
|
NotTEC
|
||||||
preflight (PreflightContext const& ctx);
|
preflight (PreflightContext const& ctx);
|
||||||
|
|
||||||
static
|
static
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ SetAccount::affectsSubsequentTransactionAuth(STTx const& tx)
|
|||||||
*uClearFlag == asfAccountTxnID);
|
*uClearFlag == asfAccountTxnID);
|
||||||
}
|
}
|
||||||
|
|
||||||
TER
|
NotTEC
|
||||||
SetAccount::preflight (PreflightContext const& ctx)
|
SetAccount::preflight (PreflightContext const& ctx)
|
||||||
{
|
{
|
||||||
auto const ret = preflight1 (ctx);
|
auto const ret = preflight1 (ctx);
|
||||||
@@ -190,7 +190,7 @@ SetAccount::preclaim(PreclaimContext const& ctx)
|
|||||||
keylet::ownerDir(id)))
|
keylet::ownerDir(id)))
|
||||||
{
|
{
|
||||||
JLOG(ctx.j.trace()) << "Retry: Owner directory not empty.";
|
JLOG(ctx.j.trace()) << "Retry: Owner directory not empty.";
|
||||||
return (ctx.flags & tapRETRY) ? terOWNERS : tecOWNERS;
|
return (ctx.flags & tapRETRY) ? TER {terOWNERS} : TER {tecOWNERS};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ public:
|
|||||||
affectsSubsequentTransactionAuth(STTx const& tx);
|
affectsSubsequentTransactionAuth(STTx const& tx);
|
||||||
|
|
||||||
static
|
static
|
||||||
TER
|
NotTEC
|
||||||
preflight (PreflightContext const& ctx);
|
preflight (PreflightContext const& ctx);
|
||||||
|
|
||||||
static
|
static
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ SetRegularKey::calculateBaseFee (
|
|||||||
return Transactor::calculateBaseFee (ctx);
|
return Transactor::calculateBaseFee (ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
TER
|
NotTEC
|
||||||
SetRegularKey::preflight (PreflightContext const& ctx)
|
SetRegularKey::preflight (PreflightContext const& ctx)
|
||||||
{
|
{
|
||||||
auto const ret = preflight1 (ctx);
|
auto const ret = preflight1 (ctx);
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
TER
|
NotTEC
|
||||||
preflight (PreflightContext const& ctx);
|
preflight (PreflightContext const& ctx);
|
||||||
|
|
||||||
static
|
static
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ namespace ripple {
|
|||||||
// setting the sfSignerListID to zero in all cases.
|
// setting the sfSignerListID to zero in all cases.
|
||||||
static std::uint32_t const defaultSignerListID_ = 0;
|
static std::uint32_t const defaultSignerListID_ = 0;
|
||||||
|
|
||||||
std::tuple<TER, std::uint32_t,
|
std::tuple<NotTEC, std::uint32_t,
|
||||||
std::vector<SignerEntries::SignerEntry>,
|
std::vector<SignerEntries::SignerEntry>,
|
||||||
SetSignerList::Operation>
|
SetSignerList::Operation>
|
||||||
SetSignerList::determineOperation(STTx const& tx,
|
SetSignerList::determineOperation(STTx const& tx,
|
||||||
@@ -69,7 +69,7 @@ SetSignerList::determineOperation(STTx const& tx,
|
|||||||
return std::make_tuple(tesSUCCESS, quorum, sign, op);
|
return std::make_tuple(tesSUCCESS, quorum, sign, op);
|
||||||
}
|
}
|
||||||
|
|
||||||
TER
|
NotTEC
|
||||||
SetSignerList::preflight (PreflightContext const& ctx)
|
SetSignerList::preflight (PreflightContext const& ctx)
|
||||||
{
|
{
|
||||||
if (! ctx.rules.enabled(featureMultiSign))
|
if (! ctx.rules.enabled(featureMultiSign))
|
||||||
@@ -95,7 +95,7 @@ SetSignerList::preflight (PreflightContext const& ctx)
|
|||||||
{
|
{
|
||||||
// Validate our settings.
|
// Validate our settings.
|
||||||
auto const account = ctx.tx.getAccountID(sfAccount);
|
auto const account = ctx.tx.getAccountID(sfAccount);
|
||||||
TER const ter =
|
NotTEC const ter =
|
||||||
validateQuorumAndSignerEntries(std::get<1>(result),
|
validateQuorumAndSignerEntries(std::get<1>(result),
|
||||||
std::get<2>(result), account, ctx.j);
|
std::get<2>(result), account, ctx.j);
|
||||||
if (ter != tesSUCCESS)
|
if (ter != tesSUCCESS)
|
||||||
@@ -141,7 +141,7 @@ SetSignerList::preCompute()
|
|||||||
return Transactor::preCompute();
|
return Transactor::preCompute();
|
||||||
}
|
}
|
||||||
|
|
||||||
TER
|
NotTEC
|
||||||
SetSignerList::validateQuorumAndSignerEntries (
|
SetSignerList::validateQuorumAndSignerEntries (
|
||||||
std::uint32_t quorum,
|
std::uint32_t quorum,
|
||||||
std::vector<SignerEntries::SignerEntry> const& signers,
|
std::vector<SignerEntries::SignerEntry> const& signers,
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
TER
|
NotTEC
|
||||||
preflight (PreflightContext const& ctx);
|
preflight (PreflightContext const& ctx);
|
||||||
|
|
||||||
TER doApply () override;
|
TER doApply () override;
|
||||||
@@ -69,14 +69,14 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
static
|
static
|
||||||
std::tuple<TER, std::uint32_t,
|
std::tuple<NotTEC, std::uint32_t,
|
||||||
std::vector<SignerEntries::SignerEntry>,
|
std::vector<SignerEntries::SignerEntry>,
|
||||||
Operation>
|
Operation>
|
||||||
determineOperation(STTx const& tx,
|
determineOperation(STTx const& tx,
|
||||||
ApplyFlags flags, beast::Journal j);
|
ApplyFlags flags, beast::Journal j);
|
||||||
|
|
||||||
static
|
static
|
||||||
TER validateQuorumAndSignerEntries (
|
NotTEC validateQuorumAndSignerEntries (
|
||||||
std::uint32_t quorum,
|
std::uint32_t quorum,
|
||||||
std::vector<SignerEntries::SignerEntry> const& signers,
|
std::vector<SignerEntries::SignerEntry> const& signers,
|
||||||
AccountID const& account,
|
AccountID const& account,
|
||||||
|
|||||||
@@ -27,7 +27,7 @@
|
|||||||
|
|
||||||
namespace ripple {
|
namespace ripple {
|
||||||
|
|
||||||
TER
|
NotTEC
|
||||||
SetTrust::preflight (PreflightContext const& ctx)
|
SetTrust::preflight (PreflightContext const& ctx)
|
||||||
{
|
{
|
||||||
auto const ret = preflight1 (ctx);
|
auto const ret = preflight1 (ctx);
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
TER
|
NotTEC
|
||||||
preflight (PreflightContext const& ctx);
|
preflight (PreflightContext const& ctx);
|
||||||
|
|
||||||
static
|
static
|
||||||
|
|||||||
@@ -25,11 +25,11 @@
|
|||||||
|
|
||||||
namespace ripple {
|
namespace ripple {
|
||||||
|
|
||||||
std::pair<std::vector<SignerEntries::SignerEntry>, TER>
|
std::pair<std::vector<SignerEntries::SignerEntry>, NotTEC>
|
||||||
SignerEntries::deserialize (
|
SignerEntries::deserialize (
|
||||||
STObject const& obj, beast::Journal journal, std::string const& annotation)
|
STObject const& obj, beast::Journal journal, std::string const& annotation)
|
||||||
{
|
{
|
||||||
std::pair<std::vector<SignerEntry>, TER> s;
|
std::pair<std::vector<SignerEntry>, NotTEC> s;
|
||||||
|
|
||||||
if (!obj.isFieldPresent (sfSignerEntries))
|
if (!obj.isFieldPresent (sfSignerEntries))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -20,9 +20,10 @@
|
|||||||
#ifndef RIPPLE_TX_IMPL_SIGNER_ENTRIES_H_INCLUDED
|
#ifndef RIPPLE_TX_IMPL_SIGNER_ENTRIES_H_INCLUDED
|
||||||
#define RIPPLE_TX_IMPL_SIGNER_ENTRIES_H_INCLUDED
|
#define RIPPLE_TX_IMPL_SIGNER_ENTRIES_H_INCLUDED
|
||||||
|
|
||||||
#include <ripple/protocol/STTx.h> // STTx::maxMultiSigners
|
#include <ripple/app/tx/impl/Transactor.h> // NotTEC
|
||||||
#include <ripple/protocol/UintTypes.h> // AccountID
|
#include <ripple/protocol/STTx.h> // STTx::maxMultiSigners
|
||||||
#include <ripple/protocol/TER.h> // temMALFORMED
|
#include <ripple/protocol/UintTypes.h> // AccountID
|
||||||
|
#include <ripple/protocol/TER.h> // temMALFORMED
|
||||||
#include <ripple/beast/utility/Journal.h> // beast::Journal
|
#include <ripple/beast/utility/Journal.h> // beast::Journal
|
||||||
|
|
||||||
namespace ripple {
|
namespace ripple {
|
||||||
@@ -60,7 +61,7 @@ public:
|
|||||||
|
|
||||||
// Deserialize a SignerEntries array from the network or from the ledger.
|
// Deserialize a SignerEntries array from the network or from the ledger.
|
||||||
static
|
static
|
||||||
std::pair<std::vector<SignerEntry>, TER>
|
std::pair<std::vector<SignerEntry>, NotTEC>
|
||||||
deserialize (
|
deserialize (
|
||||||
STObject const& obj,
|
STObject const& obj,
|
||||||
beast::Journal journal,
|
beast::Journal journal,
|
||||||
|
|||||||
@@ -35,7 +35,7 @@
|
|||||||
namespace ripple {
|
namespace ripple {
|
||||||
|
|
||||||
/** Performs early sanity checks on the txid */
|
/** Performs early sanity checks on the txid */
|
||||||
TER
|
NotTEC
|
||||||
preflight0(PreflightContext const& ctx)
|
preflight0(PreflightContext const& ctx)
|
||||||
{
|
{
|
||||||
auto const txID = ctx.tx.getTransactionID();
|
auto const txID = ctx.tx.getTransactionID();
|
||||||
@@ -51,7 +51,7 @@ preflight0(PreflightContext const& ctx)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Performs early sanity checks on the account and fee fields */
|
/** Performs early sanity checks on the account and fee fields */
|
||||||
TER
|
NotTEC
|
||||||
preflight1 (PreflightContext const& ctx)
|
preflight1 (PreflightContext const& ctx)
|
||||||
{
|
{
|
||||||
auto const ret = preflight0(ctx);
|
auto const ret = preflight0(ctx);
|
||||||
@@ -85,7 +85,7 @@ preflight1 (PreflightContext const& ctx)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Checks whether the signature appears valid */
|
/** Checks whether the signature appears valid */
|
||||||
TER
|
NotTEC
|
||||||
preflight2 (PreflightContext const& ctx)
|
preflight2 (PreflightContext const& ctx)
|
||||||
{
|
{
|
||||||
if(!( ctx.flags & tapNO_CHECK_SIGN))
|
if(!( ctx.flags & tapNO_CHECK_SIGN))
|
||||||
@@ -226,7 +226,7 @@ TER Transactor::payFee ()
|
|||||||
return tesSUCCESS;
|
return tesSUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
TER
|
NotTEC
|
||||||
Transactor::checkSeq (PreclaimContext const& ctx)
|
Transactor::checkSeq (PreclaimContext const& ctx)
|
||||||
{
|
{
|
||||||
auto const id = ctx.tx.getAccountID(sfAccount);
|
auto const id = ctx.tx.getAccountID(sfAccount);
|
||||||
@@ -327,7 +327,7 @@ TER Transactor::apply ()
|
|||||||
return doApply ();
|
return doApply ();
|
||||||
}
|
}
|
||||||
|
|
||||||
TER
|
NotTEC
|
||||||
Transactor::checkSign (PreclaimContext const& ctx)
|
Transactor::checkSign (PreclaimContext const& ctx)
|
||||||
{
|
{
|
||||||
// Make sure multisigning is enabled before we check for multisignatures.
|
// Make sure multisigning is enabled before we check for multisignatures.
|
||||||
@@ -341,7 +341,7 @@ Transactor::checkSign (PreclaimContext const& ctx)
|
|||||||
return checkSingleSign (ctx);
|
return checkSingleSign (ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
TER
|
NotTEC
|
||||||
Transactor::checkSingleSign (PreclaimContext const& ctx)
|
Transactor::checkSingleSign (PreclaimContext const& ctx)
|
||||||
{
|
{
|
||||||
auto const id = ctx.tx.getAccountID(sfAccount);
|
auto const id = ctx.tx.getAccountID(sfAccount);
|
||||||
@@ -390,7 +390,8 @@ Transactor::checkSingleSign (PreclaimContext const& ctx)
|
|||||||
return tesSUCCESS;
|
return tesSUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
TER Transactor::checkMultiSign (PreclaimContext const& ctx)
|
NotTEC
|
||||||
|
Transactor::checkMultiSign (PreclaimContext const& ctx)
|
||||||
{
|
{
|
||||||
auto const id = ctx.tx.getAccountID(sfAccount);
|
auto const id = ctx.tx.getAccountID(sfAccount);
|
||||||
// Get mTxnAccountID's SignerList and Quorum.
|
// Get mTxnAccountID's SignerList and Quorum.
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
#ifndef RIPPLE_APP_TX_TRANSACTOR_H_INCLUDED
|
#ifndef RIPPLE_APP_TX_TRANSACTOR_H_INCLUDED
|
||||||
#define RIPPLE_APP_TX_TRANSACTOR_H_INCLUDED
|
#define RIPPLE_APP_TX_TRANSACTOR_H_INCLUDED
|
||||||
|
|
||||||
|
#include <ripple/app/tx/applySteps.h>
|
||||||
#include <ripple/app/tx/impl/ApplyContext.h>
|
#include <ripple/app/tx/impl/ApplyContext.h>
|
||||||
#include <ripple/protocol/XRPAmount.h>
|
#include <ripple/protocol/XRPAmount.h>
|
||||||
#include <ripple/beast/utility/Journal.h>
|
#include <ripple/beast/utility/Journal.h>
|
||||||
@@ -116,7 +117,7 @@ public:
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
static
|
static
|
||||||
TER
|
NotTEC
|
||||||
checkSeq (PreclaimContext const& ctx);
|
checkSeq (PreclaimContext const& ctx);
|
||||||
|
|
||||||
static
|
static
|
||||||
@@ -124,7 +125,7 @@ public:
|
|||||||
checkFee (PreclaimContext const& ctx, std::uint64_t baseFee);
|
checkFee (PreclaimContext const& ctx, std::uint64_t baseFee);
|
||||||
|
|
||||||
static
|
static
|
||||||
TER
|
NotTEC
|
||||||
checkSign (PreclaimContext const& ctx);
|
checkSign (PreclaimContext const& ctx);
|
||||||
|
|
||||||
// Returns the fee in fee units, not scaled for load.
|
// Returns the fee in fee units, not scaled for load.
|
||||||
@@ -173,20 +174,20 @@ private:
|
|||||||
void setSeq ();
|
void setSeq ();
|
||||||
TER payFee ();
|
TER payFee ();
|
||||||
void claimFee (XRPAmount& fee, TER terResult, std::vector<uint256> const& removedOffers);
|
void claimFee (XRPAmount& fee, TER terResult, std::vector<uint256> const& removedOffers);
|
||||||
static TER checkSingleSign (PreclaimContext const& ctx);
|
static NotTEC checkSingleSign (PreclaimContext const& ctx);
|
||||||
static TER checkMultiSign (PreclaimContext const& ctx);
|
static NotTEC checkMultiSign (PreclaimContext const& ctx);
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Performs early sanity checks on the txid */
|
/** Performs early sanity checks on the txid */
|
||||||
TER
|
NotTEC
|
||||||
preflight0(PreflightContext const& ctx);
|
preflight0(PreflightContext const& ctx);
|
||||||
|
|
||||||
/** Performs early sanity checks on the account and fee fields */
|
/** Performs early sanity checks on the account and fee fields */
|
||||||
TER
|
NotTEC
|
||||||
preflight1 (PreflightContext const& ctx);
|
preflight1 (PreflightContext const& ctx);
|
||||||
|
|
||||||
/** Checks whether the signature appears valid */
|
/** Checks whether the signature appears valid */
|
||||||
TER
|
NotTEC
|
||||||
preflight2 (PreflightContext const& ctx);
|
preflight2 (PreflightContext const& ctx);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,7 +38,7 @@
|
|||||||
namespace ripple {
|
namespace ripple {
|
||||||
|
|
||||||
static
|
static
|
||||||
TER
|
NotTEC
|
||||||
invoke_preflight (PreflightContext const& ctx)
|
invoke_preflight (PreflightContext const& ctx)
|
||||||
{
|
{
|
||||||
switch(ctx.tx.getTxnType())
|
switch(ctx.tx.getTxnType())
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ public:
|
|||||||
}
|
}
|
||||||
TER getResultTER () const
|
TER getResultTER () const
|
||||||
{
|
{
|
||||||
return static_cast<TER> (mResult);
|
return TER::fromInt (mResult);
|
||||||
}
|
}
|
||||||
std::uint32_t getIndex () const
|
std::uint32_t getIndex () const
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -257,7 +257,7 @@ STObject TxMeta::getAsObject () const
|
|||||||
|
|
||||||
void TxMeta::addRaw (Serializer& s, TER result, std::uint32_t index)
|
void TxMeta::addRaw (Serializer& s, TER result, std::uint32_t index)
|
||||||
{
|
{
|
||||||
mResult = static_cast<int> (result);
|
mResult = TERtoInt (result);
|
||||||
mIndex = index;
|
mIndex = index;
|
||||||
assert ((mResult == 0) || ((mResult > 100) && (mResult <= 255)));
|
assert ((mResult == 0) || ((mResult > 100) && (mResult <= 255)));
|
||||||
|
|
||||||
|
|||||||
@@ -1581,8 +1581,8 @@ accountSend (ApplyView& view,
|
|||||||
// VFALCO Its laborious to have to mutate the
|
// VFALCO Its laborious to have to mutate the
|
||||||
// TER based on params everywhere
|
// TER based on params everywhere
|
||||||
terResult = view.open()
|
terResult = view.open()
|
||||||
? telFAILED_PROCESSING
|
? TER {telFAILED_PROCESSING}
|
||||||
: tecFAILED_PROCESSING;
|
: TER {tecFAILED_PROCESSING};
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -1847,8 +1847,8 @@ transferXRP (ApplyView& view,
|
|||||||
// mutating these TER everywhere
|
// mutating these TER everywhere
|
||||||
// FIXME: this logic should be moved to callers maybe?
|
// FIXME: this logic should be moved to callers maybe?
|
||||||
return view.open()
|
return view.open()
|
||||||
? telFAILED_PROCESSING
|
? TER {telFAILED_PROCESSING}
|
||||||
: tecFAILED_PROCESSING;
|
: TER {tecFAILED_PROCESSING};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decrement XRP balance.
|
// Decrement XRP balance.
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
/*
|
/*
|
||||||
This file is part of rippled: https://github.com/ripple/rippled
|
This file is part of rippled: https://github.com/ripple/rippled
|
||||||
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
Copyright (c) 2012 - 2018 Ripple Labs Inc.
|
||||||
|
|
||||||
Permission to use, copy, modify, and/or distribute this software for any
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
purpose with or without fee is hereby granted, provided that the above
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
@@ -20,7 +20,10 @@
|
|||||||
#ifndef RIPPLE_PROTOCOL_TER_H_INCLUDED
|
#ifndef RIPPLE_PROTOCOL_TER_H_INCLUDED
|
||||||
#define RIPPLE_PROTOCOL_TER_H_INCLUDED
|
#define RIPPLE_PROTOCOL_TER_H_INCLUDED
|
||||||
|
|
||||||
|
#include <ripple/json/json_value.h>
|
||||||
|
|
||||||
#include <boost/optional.hpp>
|
#include <boost/optional.hpp>
|
||||||
|
#include <ostream>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
namespace ripple {
|
namespace ripple {
|
||||||
@@ -30,9 +33,13 @@ namespace ripple {
|
|||||||
// "Transaction Engine Result"
|
// "Transaction Engine Result"
|
||||||
// or Transaction ERror.
|
// or Transaction ERror.
|
||||||
//
|
//
|
||||||
enum TER
|
using TERUnderlyingType = int;
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
enum TELcodes : TERUnderlyingType
|
||||||
{
|
{
|
||||||
// Note: Range is stable. Exact numbers are currently unstable. Use tokens.
|
// Note: Range is stable. Exact numbers are unstable. Use tokens.
|
||||||
|
|
||||||
// -399 .. -300: L Local error (transaction fee inadequate, exceeds local limit)
|
// -399 .. -300: L Local error (transaction fee inadequate, exceeds local limit)
|
||||||
// Only valid during non-consensus processing.
|
// Only valid during non-consensus processing.
|
||||||
@@ -51,7 +58,14 @@ enum TER
|
|||||||
telCAN_NOT_QUEUE_BLOCKS,
|
telCAN_NOT_QUEUE_BLOCKS,
|
||||||
telCAN_NOT_QUEUE_BLOCKED,
|
telCAN_NOT_QUEUE_BLOCKED,
|
||||||
telCAN_NOT_QUEUE_FEE,
|
telCAN_NOT_QUEUE_FEE,
|
||||||
telCAN_NOT_QUEUE_FULL,
|
telCAN_NOT_QUEUE_FULL
|
||||||
|
};
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
enum TEMcodes : TERUnderlyingType
|
||||||
|
{
|
||||||
|
// Note: Range is stable. Exact numbers are unstable. Use tokens.
|
||||||
|
|
||||||
// -299 .. -200: M Malformed (bad signature)
|
// -299 .. -200: M Malformed (bad signature)
|
||||||
// Causes:
|
// Causes:
|
||||||
@@ -95,7 +109,14 @@ enum TER
|
|||||||
|
|
||||||
// An intermediate result used internally, should never be returned.
|
// An intermediate result used internally, should never be returned.
|
||||||
temUNCERTAIN,
|
temUNCERTAIN,
|
||||||
temUNKNOWN,
|
temUNKNOWN
|
||||||
|
};
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
enum TEFcodes : TERUnderlyingType
|
||||||
|
{
|
||||||
|
// Note: Range is stable. Exact numbers are unstable. Use tokens.
|
||||||
|
|
||||||
// -199 .. -100: F
|
// -199 .. -100: F
|
||||||
// Failure (sequence number previously used)
|
// Failure (sequence number previously used)
|
||||||
@@ -127,6 +148,13 @@ enum TER
|
|||||||
tefNOT_MULTI_SIGNING,
|
tefNOT_MULTI_SIGNING,
|
||||||
tefBAD_AUTH_MASTER,
|
tefBAD_AUTH_MASTER,
|
||||||
tefINVARIANT_FAILED,
|
tefINVARIANT_FAILED,
|
||||||
|
};
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
enum TERcodes : TERUnderlyingType
|
||||||
|
{
|
||||||
|
// Note: Range is stable. Exact numbers are unstable. Use tokens.
|
||||||
|
|
||||||
// -99 .. -1: R Retry
|
// -99 .. -1: R Retry
|
||||||
// sequence too high, no funds for txn fee, originating -account
|
// sequence too high, no funds for txn fee, originating -account
|
||||||
@@ -155,7 +183,15 @@ enum TER
|
|||||||
// burden network.
|
// burden network.
|
||||||
terLAST, // Process after all other transactions
|
terLAST, // Process after all other transactions
|
||||||
terNO_RIPPLE, // Rippling not allowed
|
terNO_RIPPLE, // Rippling not allowed
|
||||||
terQUEUED, // Transaction is being held in TxQ until fee drops
|
terQUEUED // Transaction is being held in TxQ until fee drops
|
||||||
|
};
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
enum TEScodes : TERUnderlyingType
|
||||||
|
{
|
||||||
|
// Note: Exact number must stay stable. This code is stored by value
|
||||||
|
// in metadata for historic transactions.
|
||||||
|
|
||||||
// 0: S Success (success)
|
// 0: S Success (success)
|
||||||
// Causes:
|
// Causes:
|
||||||
@@ -163,7 +199,15 @@ enum TER
|
|||||||
// Implications:
|
// Implications:
|
||||||
// - Applied
|
// - Applied
|
||||||
// - Forwarded
|
// - Forwarded
|
||||||
tesSUCCESS = 0,
|
tesSUCCESS = 0
|
||||||
|
};
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
enum TECcodes : TERUnderlyingType
|
||||||
|
{
|
||||||
|
// Note: Exact numbers must stay stable. These codes are stored by
|
||||||
|
// value in metadata for historic transactions.
|
||||||
|
|
||||||
// 100 .. 159 C
|
// 100 .. 159 C
|
||||||
// Claim fee only (ripple transaction with no good paths, pay to
|
// Claim fee only (ripple transaction with no good paths, pay to
|
||||||
@@ -218,6 +262,201 @@ enum TER
|
|||||||
tecEXPIRED = 148
|
tecEXPIRED = 148
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// For generic purposes, a free function that returns the value of a TE*codes.
|
||||||
|
constexpr TERUnderlyingType TERtoInt (TELcodes v)
|
||||||
|
{ return static_cast<TERUnderlyingType>(v); }
|
||||||
|
|
||||||
|
constexpr TERUnderlyingType TERtoInt (TEMcodes v)
|
||||||
|
{ return static_cast<TERUnderlyingType>(v); }
|
||||||
|
|
||||||
|
constexpr TERUnderlyingType TERtoInt (TEFcodes v)
|
||||||
|
{ return static_cast<TERUnderlyingType>(v); }
|
||||||
|
|
||||||
|
constexpr TERUnderlyingType TERtoInt (TERcodes v)
|
||||||
|
{ return static_cast<TERUnderlyingType>(v); }
|
||||||
|
|
||||||
|
constexpr TERUnderlyingType TERtoInt (TEScodes v)
|
||||||
|
{ return static_cast<TERUnderlyingType>(v); }
|
||||||
|
|
||||||
|
constexpr TERUnderlyingType TERtoInt (TECcodes v)
|
||||||
|
{ return static_cast<TERUnderlyingType>(v); }
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// Template class that is specific to selected ranges of error codes. The
|
||||||
|
// Trait tells std::enable_if which ranges are allowed.
|
||||||
|
template <template<typename> class Trait>
|
||||||
|
class TERSubset
|
||||||
|
{
|
||||||
|
TERUnderlyingType code_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Constructors
|
||||||
|
constexpr TERSubset() : code_ (tesSUCCESS) { }
|
||||||
|
constexpr TERSubset (TERSubset const& rhs) = default;
|
||||||
|
constexpr TERSubset (TERSubset&& rhs) = default;
|
||||||
|
private:
|
||||||
|
constexpr explicit TERSubset (int rhs) : code_ (rhs) { }
|
||||||
|
public:
|
||||||
|
static constexpr TERSubset fromInt (int from)
|
||||||
|
{
|
||||||
|
return TERSubset (from);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Trait tells enable_if which types are allowed for construction.
|
||||||
|
template <typename T, typename = std::enable_if_t<Trait<T>::value>>
|
||||||
|
constexpr TERSubset (T rhs)
|
||||||
|
: code_ (TERtoInt (rhs))
|
||||||
|
{ }
|
||||||
|
|
||||||
|
// Assignment
|
||||||
|
constexpr TERSubset& operator=(TERSubset const& rhs) = default;
|
||||||
|
constexpr TERSubset& operator=(TERSubset&& rhs) = default;
|
||||||
|
|
||||||
|
// Trait tells enable_if which types are allowed for assignment.
|
||||||
|
template <typename T>
|
||||||
|
constexpr auto
|
||||||
|
operator= (T rhs) -> std::enable_if_t<Trait<T>::value, TERSubset&>
|
||||||
|
{
|
||||||
|
code_ = TERtoInt (rhs);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Conversion to bool.
|
||||||
|
explicit operator bool() const
|
||||||
|
{
|
||||||
|
return code_ != tesSUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Conversion to Json::Value allows assignment to Json::Objects
|
||||||
|
// without casting.
|
||||||
|
operator Json::Value() const
|
||||||
|
{
|
||||||
|
return Json::Value {code_};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Streaming operator.
|
||||||
|
friend std::ostream& operator<< (std::ostream& os, TERSubset const& rhs)
|
||||||
|
{
|
||||||
|
return os << rhs.code_;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the underlying value. Not a member so similarly named free
|
||||||
|
// functions can do the same work for the enums.
|
||||||
|
//
|
||||||
|
// It's worth noting that an explicit conversion operator was considered
|
||||||
|
// and rejected. Consider this case, taken from Status.h
|
||||||
|
//
|
||||||
|
// class Status {
|
||||||
|
// int code_;
|
||||||
|
// public:
|
||||||
|
// Status (TER ter)
|
||||||
|
// : code_ (ter) {}
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// This code compiles with no errors or warnings if TER has an explicit
|
||||||
|
// (unnamed) conversion to int. To avoid silent conversions like these
|
||||||
|
// we provide (only) a named conversion.
|
||||||
|
friend constexpr TERUnderlyingType TERtoInt (TERSubset v)
|
||||||
|
{
|
||||||
|
return v.code_;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Comparison operators.
|
||||||
|
// Only enabled if both arguments return int if TERtiInt is called with them.
|
||||||
|
template <typename L, typename R>
|
||||||
|
constexpr auto
|
||||||
|
operator== (L const& lhs, R const& rhs) -> std::enable_if_t<
|
||||||
|
std::is_same<decltype (TERtoInt(lhs)), int>::value &&
|
||||||
|
std::is_same<decltype (TERtoInt(rhs)), int>::value, bool>
|
||||||
|
{
|
||||||
|
return TERtoInt(lhs) == TERtoInt(rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename L, typename R>
|
||||||
|
constexpr auto
|
||||||
|
operator!= (L const& lhs, R const& rhs) -> std::enable_if_t<
|
||||||
|
std::is_same<decltype (TERtoInt(lhs)), int>::value &&
|
||||||
|
std::is_same<decltype (TERtoInt(rhs)), int>::value, bool>
|
||||||
|
{
|
||||||
|
return TERtoInt(lhs) != TERtoInt(rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename L, typename R>
|
||||||
|
constexpr auto
|
||||||
|
operator< (L const& lhs, R const& rhs) -> std::enable_if_t<
|
||||||
|
std::is_same<decltype (TERtoInt(lhs)), int>::value &&
|
||||||
|
std::is_same<decltype (TERtoInt(rhs)), int>::value, bool>
|
||||||
|
{
|
||||||
|
return TERtoInt(lhs) < TERtoInt(rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename L, typename R>
|
||||||
|
constexpr auto
|
||||||
|
operator<= (L const& lhs, R const& rhs) -> std::enable_if_t<
|
||||||
|
std::is_same<decltype (TERtoInt(lhs)), int>::value &&
|
||||||
|
std::is_same<decltype (TERtoInt(rhs)), int>::value, bool>
|
||||||
|
{
|
||||||
|
return TERtoInt(lhs) <= TERtoInt(rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename L, typename R>
|
||||||
|
constexpr auto
|
||||||
|
operator> (L const& lhs, R const& rhs) -> std::enable_if_t<
|
||||||
|
std::is_same<decltype (TERtoInt(lhs)), int>::value &&
|
||||||
|
std::is_same<decltype (TERtoInt(rhs)), int>::value, bool>
|
||||||
|
{
|
||||||
|
return TERtoInt(lhs) > TERtoInt(rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename L, typename R>
|
||||||
|
constexpr auto
|
||||||
|
operator>= (L const& lhs, R const& rhs) -> std::enable_if_t<
|
||||||
|
std::is_same<decltype (TERtoInt(lhs)), int>::value &&
|
||||||
|
std::is_same<decltype (TERtoInt(rhs)), int>::value, bool>
|
||||||
|
{
|
||||||
|
return TERtoInt(lhs) >= TERtoInt(rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Use traits to build a TERSubset that can convert from any of the TE*codes
|
||||||
|
// enums *except* TECcodes: NotTEC
|
||||||
|
|
||||||
|
// NOTE: NotTEC is useful for codes returned by preflight in transactors.
|
||||||
|
// Preflight checks occur prior to signature checking. If preflight returned
|
||||||
|
// a tec code, then a malicious user could submit a transaction with a very
|
||||||
|
// large fee and have that fee charged against an account without using that
|
||||||
|
// account's valid signature.
|
||||||
|
template <typename FROM> class CanCvtToNotTEC : public std::false_type {};
|
||||||
|
template <> class CanCvtToNotTEC<TELcodes> : public std::true_type {};
|
||||||
|
template <> class CanCvtToNotTEC<TEMcodes> : public std::true_type {};
|
||||||
|
template <> class CanCvtToNotTEC<TEFcodes> : public std::true_type {};
|
||||||
|
template <> class CanCvtToNotTEC<TERcodes> : public std::true_type {};
|
||||||
|
template <> class CanCvtToNotTEC<TEScodes> : public std::true_type {};
|
||||||
|
|
||||||
|
using NotTEC = TERSubset<CanCvtToNotTEC>;
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Use traits to build a TERSubset that can convert from any of the TE*codes
|
||||||
|
// enums as well as from NotTEC.
|
||||||
|
template <typename FROM> class CanCvtToTER : public std::false_type {};
|
||||||
|
template <> class CanCvtToTER<TELcodes> : public std::true_type {};
|
||||||
|
template <> class CanCvtToTER<TEMcodes> : public std::true_type {};
|
||||||
|
template <> class CanCvtToTER<TEFcodes> : public std::true_type {};
|
||||||
|
template <> class CanCvtToTER<TERcodes> : public std::true_type {};
|
||||||
|
template <> class CanCvtToTER<TEScodes> : public std::true_type {};
|
||||||
|
template <> class CanCvtToTER<TECcodes> : public std::true_type {};
|
||||||
|
template <> class CanCvtToTER<NotTEC> : public std::true_type {};
|
||||||
|
|
||||||
|
// TER allows all of the subsets.
|
||||||
|
using TER = TERSubset<CanCvtToTER>;
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
inline bool isTelLocal(TER x)
|
inline bool isTelLocal(TER x)
|
||||||
{
|
{
|
||||||
return ((x) >= telLOCAL_ERROR && (x) < temMALFORMED);
|
return ((x) >= telLOCAL_ERROR && (x) < temMALFORMED);
|
||||||
@@ -248,20 +487,15 @@ inline bool isTecClaim(TER x)
|
|||||||
return ((x) >= tecCLAIM);
|
return ((x) >= tecCLAIM);
|
||||||
}
|
}
|
||||||
|
|
||||||
// VFALCO TODO group these into a shell class along with the defines above.
|
|
||||||
extern
|
|
||||||
bool
|
bool
|
||||||
transResultInfo (TER code, std::string& token, std::string& text);
|
transResultInfo (TER code, std::string& token, std::string& text);
|
||||||
|
|
||||||
extern
|
|
||||||
std::string
|
std::string
|
||||||
transToken (TER code);
|
transToken (TER code);
|
||||||
|
|
||||||
extern
|
|
||||||
std::string
|
std::string
|
||||||
transHuman (TER code);
|
transHuman (TER code);
|
||||||
|
|
||||||
extern
|
|
||||||
boost::optional<TER>
|
boost::optional<TER>
|
||||||
transCode(std::string const& token);
|
transCode(std::string const& token);
|
||||||
|
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ STUInt8::getText () const
|
|||||||
{
|
{
|
||||||
std::string token, human;
|
std::string token, human;
|
||||||
|
|
||||||
if (transResultInfo (static_cast<TER> (value_), token, human))
|
if (transResultInfo (TER::fromInt (value_), token, human))
|
||||||
return human;
|
return human;
|
||||||
|
|
||||||
JLOG (debugLog().error())
|
JLOG (debugLog().error())
|
||||||
@@ -66,7 +66,7 @@ STUInt8::getJson (int) const
|
|||||||
{
|
{
|
||||||
std::string token, human;
|
std::string token, human;
|
||||||
|
|
||||||
if (transResultInfo (static_cast<TER> (value_), token, human))
|
if (transResultInfo (TER::fromInt (value_), token, human))
|
||||||
return token;
|
return token;
|
||||||
|
|
||||||
JLOG (debugLog().error())
|
JLOG (debugLog().error())
|
||||||
|
|||||||
@@ -202,14 +202,16 @@ static boost::optional<detail::STVar> parseLeaf (
|
|||||||
{
|
{
|
||||||
auto ter = transCode(strValue);
|
auto ter = transCode(strValue);
|
||||||
|
|
||||||
if (!ter || *ter < minValue || *ter > maxValue)
|
if (!ter ||
|
||||||
|
TERtoInt (*ter) < minValue ||
|
||||||
|
TERtoInt (*ter) > maxValue)
|
||||||
{
|
{
|
||||||
error = out_of_range(json_name, fieldName);
|
error = out_of_range(json_name, fieldName);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = detail::make_stvar<STUInt8>(field,
|
ret = detail::make_stvar<STUInt8>(field,
|
||||||
static_cast<std::uint8_t>(*ter));
|
static_cast<std::uint8_t>(TERtoInt (*ter)));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -28,13 +28,13 @@ namespace detail {
|
|||||||
|
|
||||||
static
|
static
|
||||||
std::unordered_map<
|
std::unordered_map<
|
||||||
std::underlying_type_t<TER>,
|
TERUnderlyingType,
|
||||||
std::pair<char const* const, char const* const>> const&
|
std::pair<char const* const, char const* const>> const&
|
||||||
transResults()
|
transResults()
|
||||||
{
|
{
|
||||||
static
|
static
|
||||||
std::unordered_map<
|
std::unordered_map<
|
||||||
std::underlying_type_t<TER>,
|
TERUnderlyingType,
|
||||||
std::pair<char const* const, char const* const>> const
|
std::pair<char const* const, char const* const>> const
|
||||||
results
|
results
|
||||||
{
|
{
|
||||||
@@ -162,8 +162,7 @@ bool transResultInfo (TER code, std::string& token, std::string& text)
|
|||||||
{
|
{
|
||||||
auto& results = detail::transResults();
|
auto& results = detail::transResults();
|
||||||
|
|
||||||
auto const r = results.find (
|
auto const r = results.find (TERtoInt (code));
|
||||||
static_cast<std::underlying_type_t<TER>> (code));
|
|
||||||
|
|
||||||
if (r == results.end())
|
if (r == results.end())
|
||||||
return false;
|
return false;
|
||||||
@@ -207,7 +206,7 @@ transCode(std::string const& token)
|
|||||||
);
|
);
|
||||||
std::unordered_map<
|
std::unordered_map<
|
||||||
std::string,
|
std::string,
|
||||||
std::underlying_type_t<TER>> const
|
TERUnderlyingType> const
|
||||||
byToken(tRange.begin(), tRange.end());
|
byToken(tRange.begin(), tRange.end());
|
||||||
return byToken;
|
return byToken;
|
||||||
}();
|
}();
|
||||||
@@ -217,7 +216,7 @@ transCode(std::string const& token)
|
|||||||
if (r == results.end())
|
if (r == results.end())
|
||||||
return boost::none;
|
return boost::none;
|
||||||
|
|
||||||
return static_cast<TER>(r->second);
|
return TER::fromInt (r->second);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // ripple
|
} // ripple
|
||||||
|
|||||||
@@ -47,23 +47,26 @@ public:
|
|||||||
|
|
||||||
Status () = default;
|
Status () = default;
|
||||||
|
|
||||||
Status (Code code, Strings d = {})
|
// The enable_if allows only integers (not enums). Prevents enum narrowing.
|
||||||
: type_ (Type::none), code_ (code), messages_ (std::move (d))
|
template <typename T,
|
||||||
|
typename = std::enable_if_t<std::is_integral<T>::value>>
|
||||||
|
Status (T code, Strings d = {})
|
||||||
|
: type_ (Type::none), code_ (code), messages_ (std::move (d))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
Status (TER ter, Strings d = {})
|
Status (TER ter, Strings d = {})
|
||||||
: type_ (Type::TER), code_ (ter), messages_ (std::move (d))
|
: type_ (Type::TER), code_ (TERtoInt (ter)), messages_ (std::move (d))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
Status (error_code_i e, Strings d = {})
|
Status (error_code_i e, Strings d = {})
|
||||||
: type_ (Type::error_code_i), code_ (e), messages_ (std::move (d))
|
: type_ (Type::error_code_i), code_ (e), messages_ (std::move (d))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
Status (error_code_i e, std::string const& s)
|
Status (error_code_i e, std::string const& s)
|
||||||
: type_ (Type::error_code_i), code_ (e), messages_ ({s})
|
: type_ (Type::error_code_i), code_ (e), messages_ ({s})
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -89,7 +92,7 @@ public:
|
|||||||
TER toTER () const
|
TER toTER () const
|
||||||
{
|
{
|
||||||
assert (type_ == Type::TER);
|
assert (type_ == Type::TER);
|
||||||
return TER (code_);
|
return TER::fromInt (code_);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns the Status as an error_code_i.
|
/** Returns the Status as an error_code_i.
|
||||||
|
|||||||
@@ -316,8 +316,9 @@ struct DepositAuth_test : public beast::unit_test::suite
|
|||||||
if (withDepositAuth)
|
if (withDepositAuth)
|
||||||
env(fset(gw1, asfDepositAuth));
|
env(fset(gw1, asfDepositAuth));
|
||||||
|
|
||||||
auto const result =
|
TER const result = (noRippleNext && noRipplePrev)
|
||||||
(noRippleNext && noRipplePrev) ? tecPATH_DRY : tesSUCCESS;
|
? TER {tecPATH_DRY}
|
||||||
|
: TER {tesSUCCESS};
|
||||||
env (pay (alice, bob, USD1(10)), path (gw1), ter (result));
|
env (pay (alice, bob, USD1(10)), path (gw1), ter (result));
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -338,8 +339,9 @@ struct DepositAuth_test : public beast::unit_test::suite
|
|||||||
if (withDepositAuth)
|
if (withDepositAuth)
|
||||||
env(fset(alice, asfDepositAuth));
|
env(fset(alice, asfDepositAuth));
|
||||||
|
|
||||||
auto const result =
|
TER const result = (noRippleNext && noRipplePrev)
|
||||||
(noRippleNext && noRipplePrev) ? tecPATH_DRY : tesSUCCESS;
|
? TER {tecPATH_DRY}
|
||||||
|
: TER {tesSUCCESS};
|
||||||
env (pay (gw1, gw2, USD2 (10)),
|
env (pay (gw1, gw2, USD2 (10)),
|
||||||
path (alice), sendmax (USD1 (10)), ter (result));
|
path (alice), sendmax (USD1 (10)), ter (result));
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1028,7 +1028,8 @@ struct Escrow_test : public beast::unit_test::suite
|
|||||||
auto const seq = env.seq(alice);
|
auto const seq = env.seq(alice);
|
||||||
env(escrow(alice, carol, XRP(1000)), finish_time(env.now() + 1s));
|
env(escrow(alice, carol, XRP(1000)), finish_time(env.now() + 1s));
|
||||||
|
|
||||||
BEAST_EXPECT((*env.meta())[sfTransactionResult] == tesSUCCESS);
|
BEAST_EXPECT((*env.meta())[sfTransactionResult] ==
|
||||||
|
static_cast<std::uint8_t>(tesSUCCESS));
|
||||||
|
|
||||||
auto const escrow = env.le(keylet::escrow(alice.id(), seq));
|
auto const escrow = env.le(keylet::escrow(alice.id(), seq));
|
||||||
BEAST_EXPECT(escrow);
|
BEAST_EXPECT(escrow);
|
||||||
@@ -1050,7 +1051,8 @@ struct Escrow_test : public beast::unit_test::suite
|
|||||||
|
|
||||||
env(escrow(alice, alice, XRP(1000)),
|
env(escrow(alice, alice, XRP(1000)),
|
||||||
finish_time(env.now() + 1s), cancel_time(env.now() + 500s));
|
finish_time(env.now() + 1s), cancel_time(env.now() + 500s));
|
||||||
BEAST_EXPECT((*env.meta())[sfTransactionResult] == tesSUCCESS);
|
BEAST_EXPECT((*env.meta())[sfTransactionResult] ==
|
||||||
|
static_cast<std::uint8_t>(tesSUCCESS));
|
||||||
env.close(5s);
|
env.close(5s);
|
||||||
auto const aa = env.le(keylet::escrow(alice.id(), aseq));
|
auto const aa = env.le(keylet::escrow(alice.id(), aseq));
|
||||||
BEAST_EXPECT(aa);
|
BEAST_EXPECT(aa);
|
||||||
@@ -1063,7 +1065,8 @@ struct Escrow_test : public beast::unit_test::suite
|
|||||||
|
|
||||||
env(escrow(bruce, bruce, XRP(1000)),
|
env(escrow(bruce, bruce, XRP(1000)),
|
||||||
finish_time(env.now() + 1s), cancel_time(env.now() + 2s));
|
finish_time(env.now() + 1s), cancel_time(env.now() + 2s));
|
||||||
BEAST_EXPECT((*env.meta())[sfTransactionResult] == tesSUCCESS);
|
BEAST_EXPECT((*env.meta())[sfTransactionResult] ==
|
||||||
|
static_cast<std::uint8_t>(tesSUCCESS));
|
||||||
env.close(5s);
|
env.close(5s);
|
||||||
auto const bb = env.le(keylet::escrow(bruce.id(), bseq));
|
auto const bb = env.le(keylet::escrow(bruce.id(), bseq));
|
||||||
BEAST_EXPECT(bb);
|
BEAST_EXPECT(bb);
|
||||||
@@ -1078,7 +1081,8 @@ struct Escrow_test : public beast::unit_test::suite
|
|||||||
env(finish(alice, alice, aseq));
|
env(finish(alice, alice, aseq));
|
||||||
{
|
{
|
||||||
BEAST_EXPECT(!env.le(keylet::escrow(alice.id(), aseq)));
|
BEAST_EXPECT(!env.le(keylet::escrow(alice.id(), aseq)));
|
||||||
BEAST_EXPECT((*env.meta())[sfTransactionResult] == tesSUCCESS);
|
BEAST_EXPECT((*env.meta())[sfTransactionResult] ==
|
||||||
|
static_cast<std::uint8_t>(tesSUCCESS));
|
||||||
|
|
||||||
ripple::Dir aod(*env.current(), keylet::ownerDir(alice.id()));
|
ripple::Dir aod(*env.current(), keylet::ownerDir(alice.id()));
|
||||||
BEAST_EXPECT(std::distance(aod.begin(), aod.end()) == 0);
|
BEAST_EXPECT(std::distance(aod.begin(), aod.end()) == 0);
|
||||||
@@ -1093,7 +1097,8 @@ struct Escrow_test : public beast::unit_test::suite
|
|||||||
env(cancel(bruce, bruce, bseq));
|
env(cancel(bruce, bruce, bseq));
|
||||||
{
|
{
|
||||||
BEAST_EXPECT(!env.le(keylet::escrow(bruce.id(), bseq)));
|
BEAST_EXPECT(!env.le(keylet::escrow(bruce.id(), bseq)));
|
||||||
BEAST_EXPECT((*env.meta())[sfTransactionResult] == tesSUCCESS);
|
BEAST_EXPECT((*env.meta())[sfTransactionResult] ==
|
||||||
|
static_cast<std::uint8_t>(tesSUCCESS));
|
||||||
|
|
||||||
ripple::Dir bod(*env.current(), keylet::ownerDir(bruce.id()));
|
ripple::Dir bod(*env.current(), keylet::ownerDir(bruce.id()));
|
||||||
BEAST_EXPECT(std::distance(bod.begin(), bod.end()) == 0);
|
BEAST_EXPECT(std::distance(bod.begin(), bod.end()) == 0);
|
||||||
@@ -1109,11 +1114,13 @@ struct Escrow_test : public beast::unit_test::suite
|
|||||||
auto const bseq = env.seq(bruce);
|
auto const bseq = env.seq(bruce);
|
||||||
|
|
||||||
env(escrow(alice, bruce, XRP(1000)), finish_time(env.now() + 1s));
|
env(escrow(alice, bruce, XRP(1000)), finish_time(env.now() + 1s));
|
||||||
BEAST_EXPECT((*env.meta())[sfTransactionResult] == tesSUCCESS);
|
BEAST_EXPECT((*env.meta())[sfTransactionResult] ==
|
||||||
|
static_cast<std::uint8_t>(tesSUCCESS));
|
||||||
env.close(5s);
|
env.close(5s);
|
||||||
env(escrow(bruce, carol, XRP(1000)),
|
env(escrow(bruce, carol, XRP(1000)),
|
||||||
finish_time(env.now() + 1s), cancel_time(env.now() + 2s));
|
finish_time(env.now() + 1s), cancel_time(env.now() + 2s));
|
||||||
BEAST_EXPECT((*env.meta())[sfTransactionResult] == tesSUCCESS);
|
BEAST_EXPECT((*env.meta())[sfTransactionResult] ==
|
||||||
|
static_cast<std::uint8_t>(tesSUCCESS));
|
||||||
env.close(5s);
|
env.close(5s);
|
||||||
|
|
||||||
auto const ab = env.le(keylet::escrow(alice.id(), aseq));
|
auto const ab = env.le(keylet::escrow(alice.id(), aseq));
|
||||||
|
|||||||
@@ -753,8 +753,9 @@ struct Flow_test : public beast::unit_test::suite
|
|||||||
env (offer (bob, XRP (50), USD (50)));
|
env (offer (bob, XRP (50), USD (50)));
|
||||||
env (offer (bob, XRP (100), USD (50)));
|
env (offer (bob, XRP (100), USD (50)));
|
||||||
|
|
||||||
auto expectedResult =
|
TER const expectedResult = closeTime < fix1141Time ()
|
||||||
closeTime < fix1141Time () ? tecPATH_DRY : tesSUCCESS;
|
? TER {tecPATH_DRY}
|
||||||
|
: TER {tesSUCCESS};
|
||||||
env (pay (alice, carol, USD (100)), path (~USD), sendmax (XRP (100)),
|
env (pay (alice, carol, USD (100)), path (~USD), sendmax (XRP (100)),
|
||||||
txflags (tfNoRippleDirect | tfPartialPayment | tfLimitQuality),
|
txflags (tfNoRippleDirect | tfPartialPayment | tfLimitQuality),
|
||||||
ter (expectedResult));
|
ter (expectedResult));
|
||||||
@@ -1131,7 +1132,7 @@ struct Flow_test : public beast::unit_test::suite
|
|||||||
|
|
||||||
env(pay(alice, alice, XRP(1)), path(gw, bob, ~XRP),
|
env(pay(alice, alice, XRP(1)), path(gw, bob, ~XRP),
|
||||||
sendmax(gw["USD"](1000)), txflags(tfNoRippleDirect),
|
sendmax(gw["USD"](1000)), txflags(tfNoRippleDirect),
|
||||||
ter(withFix ? tecPATH_DRY : tesSUCCESS));
|
ter(withFix ? TER {tecPATH_DRY} : TER {tesSUCCESS}));
|
||||||
env.close();
|
env.close();
|
||||||
|
|
||||||
if (withFix)
|
if (withFix)
|
||||||
@@ -1145,7 +1146,7 @@ struct Flow_test : public beast::unit_test::suite
|
|||||||
|
|
||||||
env(pay (carol, carol, gw["USD"](1000)), path(~bob["USD"], gw),
|
env(pay (carol, carol, gw["USD"](1000)), path(~bob["USD"], gw),
|
||||||
sendmax(XRP(100000)), txflags(tfNoRippleDirect),
|
sendmax(XRP(100000)), txflags(tfNoRippleDirect),
|
||||||
ter(withFix ? tecPATH_DRY : tesSUCCESS));
|
ter(withFix ? TER {tecPATH_DRY} : TER {tesSUCCESS}));
|
||||||
env.close();
|
env.close();
|
||||||
|
|
||||||
pass();
|
pass();
|
||||||
@@ -1189,7 +1190,7 @@ struct Flow_test : public beast::unit_test::suite
|
|||||||
|
|
||||||
env(pay(alice, alice, USD(1000)), path(~bob["USD"], bob, gw),
|
env(pay(alice, alice, USD(1000)), path(~bob["USD"], bob, gw),
|
||||||
sendmax(XRP(1)), txflags(tfNoRippleDirect),
|
sendmax(XRP(1)), txflags(tfNoRippleDirect),
|
||||||
ter(withFix ? tecPATH_DRY : tesSUCCESS));
|
ter(withFix ? TER {tecPATH_DRY} : TER {tesSUCCESS}));
|
||||||
env.close();
|
env.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -239,7 +239,7 @@ public:
|
|||||||
env (offer (alice, XRP (5), USD (2)),
|
env (offer (alice, XRP (5), USD (2)),
|
||||||
json (sfExpiration.fieldName, lastClose(env)),
|
json (sfExpiration.fieldName, lastClose(env)),
|
||||||
json (jss::OfferSequence, offer2Seq),
|
json (jss::OfferSequence, offer2Seq),
|
||||||
ter (featChecks ? tecEXPIRED : tesSUCCESS));
|
ter (featChecks ? TER {tecEXPIRED} : TER {tesSUCCESS}));
|
||||||
env.close();
|
env.close();
|
||||||
|
|
||||||
env.require (offers (alice, 2));
|
env.require (offers (alice, 2));
|
||||||
@@ -289,8 +289,8 @@ public:
|
|||||||
(hasFeature(env, featureFeeEscalation) &&
|
(hasFeature(env, featureFeeEscalation) &&
|
||||||
!hasFeature(env, fix1513));
|
!hasFeature(env, fix1513));
|
||||||
// Will fail without the underflow fix
|
// Will fail without the underflow fix
|
||||||
auto expectedResult = *stAmountCalcSwitchover ?
|
TER const expectedResult = *stAmountCalcSwitchover ?
|
||||||
tesSUCCESS : tecPATH_PARTIAL;
|
TER {tesSUCCESS} : TER {tecPATH_PARTIAL};
|
||||||
env (pay (alice, bob, EUR (epsilon)), path (~EUR),
|
env (pay (alice, bob, EUR (epsilon)), path (~EUR),
|
||||||
sendmax (USD (100)), ter (expectedResult));
|
sendmax (USD (100)), ter (expectedResult));
|
||||||
}
|
}
|
||||||
@@ -959,7 +959,7 @@ public:
|
|||||||
|
|
||||||
env (offer (alice, xrpOffer, usdOffer),
|
env (offer (alice, xrpOffer, usdOffer),
|
||||||
json (sfExpiration.fieldName, lastClose(env)),
|
json (sfExpiration.fieldName, lastClose(env)),
|
||||||
ter (featChecks ? tecEXPIRED : tesSUCCESS));
|
ter (featChecks ? TER {tecEXPIRED} : TER {tesSUCCESS}));
|
||||||
|
|
||||||
env.require (
|
env.require (
|
||||||
balance (alice, startBalance - f - f),
|
balance (alice, startBalance - f - f),
|
||||||
@@ -3422,7 +3422,7 @@ public:
|
|||||||
|
|
||||||
// Determine which TEC code we expect.
|
// Determine which TEC code we expect.
|
||||||
TER const tecExpect =
|
TER const tecExpect =
|
||||||
features[featureFlow] ? temBAD_PATH : tecPATH_DRY;
|
features[featureFlow] ? TER {temBAD_PATH} : TER {tecPATH_DRY};
|
||||||
|
|
||||||
// This payment caused the assert.
|
// This payment caused the assert.
|
||||||
env (pay (ann, ann, D_BUX(30)),
|
env (pay (ann, ann, D_BUX(30)),
|
||||||
@@ -4397,7 +4397,7 @@ public:
|
|||||||
// create an offer to buy their own currency. After FlowCross
|
// create an offer to buy their own currency. After FlowCross
|
||||||
// they can.
|
// they can.
|
||||||
env (offer (gw, gwUSD(40), XRP(4000)),
|
env (offer (gw, gwUSD(40), XRP(4000)),
|
||||||
ter (flowCross ? tesSUCCESS : tecNO_LINE));
|
ter (flowCross ? TER {tesSUCCESS} : TER {tecNO_LINE}));
|
||||||
env.close();
|
env.close();
|
||||||
|
|
||||||
env.require (offers (gw, flowCross ? 1 : 0));
|
env.require (offers (gw, flowCross ? 1 : 0));
|
||||||
|
|||||||
@@ -1375,7 +1375,7 @@ struct PayStrand_test : public beast::unit_test::suite
|
|||||||
env(offer(bob, XRP(100), USD(100)), txflags(tfPassive));
|
env(offer(bob, XRP(100), USD(100)), txflags(tfPassive));
|
||||||
env(offer(bob, USD(100), XRP(100)), txflags(tfPassive));
|
env(offer(bob, USD(100), XRP(100)), txflags(tfPassive));
|
||||||
|
|
||||||
auto const expectedResult = [&] {
|
auto const expectedResult = [&] () -> TER {
|
||||||
if (features[featureFlow] && !features[fix1373])
|
if (features[featureFlow] && !features[fix1373])
|
||||||
return tesSUCCESS;
|
return tesSUCCESS;
|
||||||
return temBAD_PATH_LOOP;
|
return temBAD_PATH_LOOP;
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ struct JTx
|
|||||||
{
|
{
|
||||||
Json::Value jv;
|
Json::Value jv;
|
||||||
requires_t requires;
|
requires_t requires;
|
||||||
boost::optional<TER> ter = tesSUCCESS;
|
boost::optional<TER> ter = TER {tesSUCCESS};
|
||||||
bool fill_fee = true;
|
bool fill_fee = true;
|
||||||
bool fill_seq = true;
|
bool fill_seq = true;
|
||||||
bool fill_sig = true;
|
bool fill_sig = true;
|
||||||
|
|||||||
@@ -278,8 +278,7 @@ Env::parseResult(Json::Value const& jr)
|
|||||||
TER ter;
|
TER ter;
|
||||||
if (jr.isObject() && jr.isMember(jss::result) &&
|
if (jr.isObject() && jr.isMember(jss::result) &&
|
||||||
jr[jss::result].isMember(jss::engine_result_code))
|
jr[jss::result].isMember(jss::engine_result_code))
|
||||||
ter = static_cast<TER>(
|
ter = TER::fromInt (jr[jss::result][jss::engine_result_code].asInt());
|
||||||
jr[jss::result][jss::engine_result_code].asInt());
|
|
||||||
else
|
else
|
||||||
ter = temINVALID;
|
ter = temINVALID;
|
||||||
return std::make_pair(ter,
|
return std::make_pair(ter,
|
||||||
|
|||||||
@@ -94,15 +94,16 @@ class Invariants_test : public beast::unit_test::suite
|
|||||||
|
|
||||||
BEAST_EXPECT(precheck(A1, A2, ac));
|
BEAST_EXPECT(precheck(A1, A2, ac));
|
||||||
|
|
||||||
auto tr = tesSUCCESS;
|
TER tr = tesSUCCESS;
|
||||||
// invoke check twice to cover tec and tef cases
|
// invoke check twice to cover tec and tef cases
|
||||||
for (auto i : {0,1})
|
for (auto i : {0,1})
|
||||||
{
|
{
|
||||||
tr = ac.checkInvariants(tr);
|
tr = ac.checkInvariants(tr);
|
||||||
if (enabled)
|
if (enabled)
|
||||||
{
|
{
|
||||||
BEAST_EXPECT(
|
BEAST_EXPECT(tr == (i == 0
|
||||||
tr == (i == 0 ? tecINVARIANT_FAILED : tefINVARIANT_FAILED));
|
? TER {tecINVARIANT_FAILED}
|
||||||
|
: TER {tefINVARIANT_FAILED}));
|
||||||
BEAST_EXPECT(
|
BEAST_EXPECT(
|
||||||
boost::starts_with(sink.strm_.str(), "Invariant failed:") ||
|
boost::starts_with(sink.strm_.str(), "Invariant failed:") ||
|
||||||
boost::starts_with(sink.strm_.str(),
|
boost::starts_with(sink.strm_.str(),
|
||||||
|
|||||||
@@ -20,6 +20,9 @@
|
|||||||
#include <ripple/protocol/TER.h>
|
#include <ripple/protocol/TER.h>
|
||||||
#include <ripple/beast/unit_test.h>
|
#include <ripple/beast/unit_test.h>
|
||||||
|
|
||||||
|
#include <tuple>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
namespace ripple {
|
namespace ripple {
|
||||||
|
|
||||||
struct TER_test : public beast::unit_test::suite
|
struct TER_test : public beast::unit_test::suite
|
||||||
@@ -29,7 +32,7 @@ struct TER_test : public beast::unit_test::suite
|
|||||||
{
|
{
|
||||||
for (auto i = -400; i < 400; ++i)
|
for (auto i = -400; i < 400; ++i)
|
||||||
{
|
{
|
||||||
TER t = static_cast<TER>(i);
|
TER t = TER::fromInt (i);
|
||||||
auto inRange = isTelLocal(t) ||
|
auto inRange = isTelLocal(t) ||
|
||||||
isTemMalformed(t) ||
|
isTemMalformed(t) ||
|
||||||
isTefFailure(t) ||
|
isTefFailure(t) ||
|
||||||
@@ -49,13 +52,214 @@ struct TER_test : public beast::unit_test::suite
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Helper template that makes sure two types are not convertible or
|
||||||
|
// assignable if not the same.
|
||||||
|
// o I1 one tuple index.
|
||||||
|
// o I2 other tuple index.
|
||||||
|
// o Tup is expected to be a tuple.
|
||||||
|
// It's a functor, rather than a function template, since a class template
|
||||||
|
// can be a template argument without being full specified.
|
||||||
|
template<std::size_t I1, std::size_t I2>
|
||||||
|
class NotConvertible
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
template<typename Tup>
|
||||||
|
void operator()(Tup const& tup, beast::unit_test::suite&) const
|
||||||
|
{
|
||||||
|
// Entries in the tuple should not be convertible or assignable
|
||||||
|
// unless they are the same types.
|
||||||
|
using To_t = std::decay_t<decltype (std::get<I1>(tup))>;
|
||||||
|
using From_t = std::decay_t<decltype (std::get<I2>(tup))>;
|
||||||
|
static_assert (std::is_same<From_t, To_t>::value ==
|
||||||
|
std::is_convertible<From_t, To_t>::value, "Convert err");
|
||||||
|
static_assert (std::is_same<To_t, From_t>::value ==
|
||||||
|
std::is_constructible<To_t, From_t>::value, "Construct err");
|
||||||
|
static_assert (std::is_same <To_t, From_t>::value ==
|
||||||
|
std::is_assignable<To_t&, From_t const&>::value, "Assign err");
|
||||||
|
|
||||||
|
// Assignment or conversion from integer to type should never work.
|
||||||
|
static_assert (
|
||||||
|
! std::is_convertible<int, To_t>::value, "Convert err");
|
||||||
|
static_assert (
|
||||||
|
! std::is_constructible<To_t, int>::value, "Construct err");
|
||||||
|
static_assert (
|
||||||
|
! std::is_assignable<To_t&, int const&>::value, "Assign err");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Fast iteration over the tuple.
|
||||||
|
template<std::size_t I1, std::size_t I2,
|
||||||
|
template<std::size_t, std::size_t> class Func, typename Tup>
|
||||||
|
std::enable_if_t<I1 != 0>
|
||||||
|
testIterate (Tup const& tup, beast::unit_test::suite& suite)
|
||||||
|
{
|
||||||
|
Func<I1, I2> func;
|
||||||
|
func (tup, suite);
|
||||||
|
testIterate<I1 - 1, I2, Func>(tup, suite);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Slow iteration over the tuple.
|
||||||
|
template<std::size_t I1, std::size_t I2,
|
||||||
|
template<std::size_t, std::size_t> class Func, typename Tup>
|
||||||
|
std::enable_if_t<I1 == 0 && I2 != 0>
|
||||||
|
testIterate (Tup const& tup, beast::unit_test::suite& suite)
|
||||||
|
{
|
||||||
|
Func<I1, I2> func;
|
||||||
|
func (tup, suite);
|
||||||
|
testIterate<std::tuple_size<Tup>::value - 1, I2 - 1, Func>(tup, suite);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finish iteration over the tuple.
|
||||||
|
template<std::size_t I1, std::size_t I2,
|
||||||
|
template<std::size_t, std::size_t> class Func, typename Tup>
|
||||||
|
std::enable_if_t<I1 == 0 && I2 == 0>
|
||||||
|
testIterate (Tup const& tup, beast::unit_test::suite& suite)
|
||||||
|
{
|
||||||
|
Func<I1, I2> func;
|
||||||
|
func (tup, suite);
|
||||||
|
}
|
||||||
|
|
||||||
|
void testConversion()
|
||||||
|
{
|
||||||
|
// Verify that valid conversions are valid and invalid conversions
|
||||||
|
// are not valid.
|
||||||
|
|
||||||
|
// Examples of each kind of enum.
|
||||||
|
static auto const terEnums = std::make_tuple (telLOCAL_ERROR,
|
||||||
|
temMALFORMED, tefFAILURE, terRETRY, tesSUCCESS, tecCLAIM);
|
||||||
|
static const int hiIndex {
|
||||||
|
std::tuple_size<decltype (terEnums)>::value - 1};
|
||||||
|
|
||||||
|
// Verify that enums cannot be converted to other enum types.
|
||||||
|
testIterate<hiIndex, hiIndex, NotConvertible> (terEnums, *this);
|
||||||
|
|
||||||
|
// Lambda that verifies assignability and convertibility.
|
||||||
|
auto isConvertable = [] (auto from, auto to)
|
||||||
|
{
|
||||||
|
using From_t = std::decay_t<decltype (from)>;
|
||||||
|
using To_t = std::decay_t<decltype (to)>;
|
||||||
|
static_assert (
|
||||||
|
std::is_convertible<From_t, To_t>::value, "Convert err");
|
||||||
|
static_assert (
|
||||||
|
std::is_constructible<To_t, From_t>::value, "Construct err");
|
||||||
|
static_assert (
|
||||||
|
std::is_assignable<To_t&, From_t const&>::value, "Assign err");
|
||||||
|
};
|
||||||
|
|
||||||
|
// Verify the right types convert to NotTEC.
|
||||||
|
NotTEC const notTec;
|
||||||
|
isConvertable (telLOCAL_ERROR, notTec);
|
||||||
|
isConvertable (temMALFORMED, notTec);
|
||||||
|
isConvertable (tefFAILURE, notTec);
|
||||||
|
isConvertable (terRETRY, notTec);
|
||||||
|
isConvertable (tesSUCCESS, notTec);
|
||||||
|
isConvertable (notTec, notTec);
|
||||||
|
|
||||||
|
// Lambda that verifies types and not assignable or convertible.
|
||||||
|
auto notConvertible = [] (auto from, auto to)
|
||||||
|
{
|
||||||
|
using To_t = std::decay_t<decltype (to)>;
|
||||||
|
using From_t = std::decay_t<decltype (from)>;
|
||||||
|
static_assert (
|
||||||
|
!std::is_convertible<From_t, To_t>::value, "Convert err");
|
||||||
|
static_assert (
|
||||||
|
!std::is_constructible<To_t, From_t>::value, "Construct err");
|
||||||
|
static_assert (
|
||||||
|
!std::is_assignable<To_t&, From_t const&>::value, "Assign err");
|
||||||
|
};
|
||||||
|
|
||||||
|
// Verify types that shouldn't convert to NotTEC.
|
||||||
|
TER const ter;
|
||||||
|
notConvertible (tecCLAIM, notTec);
|
||||||
|
notConvertible (ter, notTec);
|
||||||
|
notConvertible (4, notTec);
|
||||||
|
|
||||||
|
// Verify the right types convert to TER.
|
||||||
|
isConvertable (telLOCAL_ERROR, ter);
|
||||||
|
isConvertable (temMALFORMED, ter);
|
||||||
|
isConvertable (tefFAILURE, ter);
|
||||||
|
isConvertable (terRETRY, ter);
|
||||||
|
isConvertable (tesSUCCESS, ter);
|
||||||
|
isConvertable (tecCLAIM, ter);
|
||||||
|
isConvertable (notTec, ter);
|
||||||
|
isConvertable (ter, ter);
|
||||||
|
|
||||||
|
// Verify that you can't convert from int to ter.
|
||||||
|
notConvertible (4, ter);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper template that makes sure two types are comparable. Also
|
||||||
|
// verifies that one of the types does not compare to int.
|
||||||
|
// o I1 one tuple index.
|
||||||
|
// o I2 other tuple index.
|
||||||
|
// o Tup is expected to be a tuple.
|
||||||
|
// It's a functor, rather than a function template, since a class template
|
||||||
|
// can be a template argument without being full specified.
|
||||||
|
template<std::size_t I1, std::size_t I2>
|
||||||
|
class CheckComparable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
template<typename Tup>
|
||||||
|
void operator()(Tup const& tup, beast::unit_test::suite& suite) const
|
||||||
|
{
|
||||||
|
// All entries in the tuple should be comparable one to the other.
|
||||||
|
auto const lhs = std::get<I1>(tup);
|
||||||
|
auto const rhs = std::get<I2>(tup);
|
||||||
|
|
||||||
|
static_assert (std::is_same<
|
||||||
|
decltype (operator== (lhs, rhs)), bool>::value, "== err");
|
||||||
|
|
||||||
|
static_assert (std::is_same<
|
||||||
|
decltype (operator!= (lhs, rhs)), bool>::value, "!= err");
|
||||||
|
|
||||||
|
static_assert (std::is_same<
|
||||||
|
decltype (operator< (lhs, rhs)), bool>::value, "< err");
|
||||||
|
|
||||||
|
static_assert (std::is_same<
|
||||||
|
decltype (operator<= (lhs, rhs)), bool>::value, "<= err");
|
||||||
|
|
||||||
|
static_assert (std::is_same<
|
||||||
|
decltype (operator> (lhs, rhs)), bool>::value, "> err");
|
||||||
|
|
||||||
|
static_assert (std::is_same<
|
||||||
|
decltype (operator>= (lhs, rhs)), bool>::value, ">= err");
|
||||||
|
|
||||||
|
// Make sure a sampling of TER types exhibit the expected behavior
|
||||||
|
// for all comparison operators.
|
||||||
|
suite.expect ((lhs == rhs) == (TERtoInt (lhs) == TERtoInt (rhs)));
|
||||||
|
suite.expect ((lhs != rhs) == (TERtoInt (lhs) != TERtoInt (rhs)));
|
||||||
|
suite.expect ((lhs < rhs) == (TERtoInt (lhs) < TERtoInt (rhs)));
|
||||||
|
suite.expect ((lhs <= rhs) == (TERtoInt (lhs) <= TERtoInt (rhs)));
|
||||||
|
suite.expect ((lhs > rhs) == (TERtoInt (lhs) > TERtoInt (rhs)));
|
||||||
|
suite.expect ((lhs >= rhs) == (TERtoInt (lhs) >= TERtoInt (rhs)));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void testComparison()
|
||||||
|
{
|
||||||
|
// All of the TER-related types should be comparable.
|
||||||
|
|
||||||
|
// Examples of all the types we expect to successfully compare.
|
||||||
|
static auto const ters = std::make_tuple (telLOCAL_ERROR, temMALFORMED,
|
||||||
|
tefFAILURE, terRETRY, tesSUCCESS, tecCLAIM,
|
||||||
|
NotTEC {telLOCAL_ERROR}, TER {tecCLAIM});
|
||||||
|
static const int hiIndex {
|
||||||
|
std::tuple_size<decltype (ters)>::value - 1};
|
||||||
|
|
||||||
|
// Verify that all types in the ters tuple can be compared with all
|
||||||
|
// the other types in ters.
|
||||||
|
testIterate<hiIndex, hiIndex, CheckComparable> (ters, *this);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
run() override
|
run() override
|
||||||
{
|
{
|
||||||
testTransResultInfo();
|
testTransResultInfo();
|
||||||
|
testConversion();
|
||||||
|
testComparison();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
BEAST_DEFINE_TESTSUITE(TER,protocol,ripple);
|
BEAST_DEFINE_TESTSUITE(TER,protocol,ripple);
|
||||||
|
|
||||||
}
|
} //namespace ripple
|
||||||
|
|||||||
Reference in New Issue
Block a user