Validate fee during preflight

This commit is contained in:
Nik Bougalis
2015-07-31 11:25:31 -07:00
parent 22a8e25538
commit 5b90ccf65d
13 changed files with 105 additions and 40 deletions

View File

@@ -29,6 +29,10 @@ namespace ripple {
TER TER
CancelOffer::preflight (PreflightContext const& ctx) CancelOffer::preflight (PreflightContext const& ctx)
{ {
auto const ret = preflight1 (ctx);
if (!isTesSuccess (ret))
return ret;
auto const uTxFlags = ctx.tx.getFlags(); auto const uTxFlags = ctx.tx.getFlags();
if (uTxFlags & tfUniversalMask) if (uTxFlags & tfUniversalMask)
@@ -46,7 +50,7 @@ CancelOffer::preflight (PreflightContext const& ctx)
return temBAD_SEQUENCE; return temBAD_SEQUENCE;
} }
return Transactor::preflight(ctx); return preflight2(ctx);
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------

View File

@@ -32,7 +32,12 @@ CancelTicket::preflight (PreflightContext const& ctx)
if (! (ctx.flags & tapENABLE_TESTING)) if (! (ctx.flags & tapENABLE_TESTING))
return temDISABLED; return temDISABLED;
#endif #endif
return Transactor::preflight(ctx);
auto const ret = preflight1 (ctx);
if (!isTesSuccess (ret))
return ret;
return preflight2 (ctx);
} }
TER TER

View File

@@ -32,13 +32,19 @@ TER
Change::preflight (PreflightContext const& ctx) Change::preflight (PreflightContext const& ctx)
{ {
auto account = ctx.tx.getAccountID(sfAccount); auto account = ctx.tx.getAccountID(sfAccount);
if (account != zero)
if (account.isNonZero ())
{ {
JLOG(ctx.j.warning) << "Bad source id"; JLOG(ctx.j.warning) << "Bad source id";
return temBAD_SRC_ACCOUNT; return temBAD_SRC_ACCOUNT;
} }
auto const fee = ctx.tx.getTransactionFee ();
if (!fee.native () || fee != beast::zero)
{
JLOG(ctx.j.warning) << "Non-zero fee";
return temBAD_FEE;
}
return tesSUCCESS; return tesSUCCESS;
} }
@@ -89,7 +95,7 @@ Change::checkSeq()
TER TER
Change::payFee() Change::payFee()
{ {
if (tx().getTransactionFee () != STAmount ()) if (tx().getTransactionFee () != beast::zero)
{ {
j_.warning << "Non-zero fee"; j_.warning << "Non-zero fee";
return temBAD_FEE; return temBAD_FEE;

View File

@@ -36,6 +36,10 @@ namespace ripple {
TER TER
CreateOffer::preflight (PreflightContext const& ctx) CreateOffer::preflight (PreflightContext const& ctx)
{ {
auto const ret = preflight1 (ctx);
if (!isTesSuccess (ret))
return ret;
auto& tx = ctx.tx; auto& tx = ctx.tx;
auto& j = ctx.j; auto& j = ctx.j;
@@ -123,7 +127,7 @@ CreateOffer::preflight (PreflightContext const& ctx)
return temBAD_ISSUER; return temBAD_ISSUER;
} }
return Transactor::preflight(ctx); return preflight2(ctx);
} }
TER TER

View File

@@ -33,6 +33,10 @@ CreateTicket::preflight (PreflightContext const& ctx)
return temDISABLED; return temDISABLED;
#endif #endif
auto const ret = preflight1 (ctx);
if (!isTesSuccess (ret))
return ret;
if (ctx.tx.isFieldPresent (sfExpiration)) if (ctx.tx.isFieldPresent (sfExpiration))
{ {
if (ctx.tx.getFieldU32 (sfExpiration) == 0) if (ctx.tx.getFieldU32 (sfExpiration) == 0)
@@ -43,7 +47,7 @@ CreateTicket::preflight (PreflightContext const& ctx)
} }
} }
return Transactor::preflight(ctx); return preflight2 (ctx);
} }
STAmount STAmount

View File

@@ -41,6 +41,10 @@ allowDeliverMin (ApplyView const& view)
TER TER
Payment::preflight (PreflightContext const& ctx) Payment::preflight (PreflightContext const& ctx)
{ {
auto const ret = preflight1 (ctx);
if (!isTesSuccess (ret))
return ret;
auto& tx = ctx.tx; auto& tx = ctx.tx;
auto& j = ctx.j; auto& j = ctx.j;
@@ -187,7 +191,7 @@ Payment::preflight (PreflightContext const& ctx)
} }
} }
return Transactor::preflight(ctx); return preflight2 (ctx);
} }
TER TER

View File

@@ -31,6 +31,10 @@ namespace ripple {
TER TER
SetAccount::preflight (PreflightContext const& ctx) SetAccount::preflight (PreflightContext const& ctx)
{ {
auto const ret = preflight1 (ctx);
if (!isTesSuccess (ret))
return ret;
auto& tx = ctx.tx; auto& tx = ctx.tx;
auto& j = ctx.j; auto& j = ctx.j;
@@ -99,7 +103,7 @@ SetAccount::preflight (PreflightContext const& ctx)
} }
} }
return Transactor::preflight(ctx); return preflight2(ctx);
} }
TER TER

View File

@@ -44,6 +44,10 @@ SetRegularKey::calculateBaseFee ()
TER TER
SetRegularKey::preflight (PreflightContext const& ctx) SetRegularKey::preflight (PreflightContext const& ctx)
{ {
auto const ret = preflight1 (ctx);
if (!isTesSuccess (ret))
return ret;
std::uint32_t const uTxFlags = ctx.tx.getFlags (); std::uint32_t const uTxFlags = ctx.tx.getFlags ();
if (uTxFlags & tfUniversalMask) if (uTxFlags & tfUniversalMask)
@@ -54,7 +58,7 @@ SetRegularKey::preflight (PreflightContext const& ctx)
return temINVALID_FLAG; return temINVALID_FLAG;
} }
return Transactor::preflight(ctx); return preflight2(ctx);
} }
TER TER

View File

@@ -80,6 +80,10 @@ SetSignerList::preflight (PreflightContext const& ctx)
return temDISABLED; return temDISABLED;
#endif #endif
auto const ret = preflight1 (ctx);
if (!isTesSuccess (ret))
return ret;
auto const result = determineOperation(ctx.tx, ctx.flags, ctx.j); auto const result = determineOperation(ctx.tx, ctx.flags, ctx.j);
if (std::get<0>(result) != tesSUCCESS) if (std::get<0>(result) != tesSUCCESS)
return std::get<0>(result); return std::get<0>(result);
@@ -105,7 +109,7 @@ SetSignerList::preflight (PreflightContext const& ctx)
} }
} }
return Transactor::preflight(ctx); return preflight2 (ctx);
} }
TER TER

View File

@@ -30,6 +30,10 @@ namespace ripple {
TER TER
SetTrust::preflight (PreflightContext const& ctx) SetTrust::preflight (PreflightContext const& ctx)
{ {
auto const ret = preflight1 (ctx);
if (!isTesSuccess (ret))
return ret;
auto& tx = ctx.tx; auto& tx = ctx.tx;
auto& j = ctx.j; auto& j = ctx.j;
@@ -79,7 +83,7 @@ SetTrust::preflight (PreflightContext const& ctx)
return temDST_NEEDED; return temDST_NEEDED;
} }
return Transactor::preflight(ctx); return preflight2 (ctx);
} }
TER TER

View File

@@ -109,7 +109,7 @@ namespace ripple {
SusPayCancel SusPayCancel
Any account may submit a SusPayCancel transaction. Any account may submit a SusPayCancel transaction.
If the SusPay ledger entry does not specify a If the SusPay ledger entry does not specify a
sfCancelAfter, the cancel transaction will fail. sfCancelAfter, the cancel transaction will fail.
@@ -136,6 +136,10 @@ SusPayCreate::preflight (PreflightContext const& ctx)
ctx.config.features)) ctx.config.features))
return temDISABLED; return temDISABLED;
auto const ret = preflight1 (ctx);
if (!isTesSuccess (ret))
return ret;
if (! isXRP(ctx.tx[sfAmount])) if (! isXRP(ctx.tx[sfAmount]))
return temBAD_AMOUNT; return temBAD_AMOUNT;
@@ -150,7 +154,7 @@ SusPayCreate::preflight (PreflightContext const& ctx)
ctx.tx[sfCancelAfter] <= ctx.tx[sfFinishAfter]) ctx.tx[sfCancelAfter] <= ctx.tx[sfFinishAfter])
return temBAD_EXPIRATION; return temBAD_EXPIRATION;
return Transactor::preflight(ctx); return preflight2 (ctx);
} }
TER TER
@@ -187,12 +191,12 @@ SusPayCreate::doApply()
auto const sle = ctx_.view().peek( auto const sle = ctx_.view().peek(
keylet::account(account)); keylet::account(account));
if (XRPAmount(STAmount((*sle)[sfBalance]).mantissa()) < if (XRPAmount(STAmount((*sle)[sfBalance]).mantissa()) <
XRPAmount(ctx_.view().fees().accountReserve( XRPAmount(ctx_.view().fees().accountReserve(
(*sle)[sfOwnerCount] + 1))) (*sle)[sfOwnerCount] + 1)))
return tecINSUFFICIENT_RESERVE; return tecINSUFFICIENT_RESERVE;
if (XRPAmount(STAmount((*sle)[sfBalance]).mantissa()) < if (XRPAmount(STAmount((*sle)[sfBalance]).mantissa()) <
amount + XRPAmount(ctx_.view().fees().accountReserve( amount + XRPAmount(ctx_.view().fees().accountReserve(
(*sle)[sfOwnerCount] + 1))) (*sle)[sfOwnerCount] + 1)))
return tecUNFUNDED; return tecUNFUNDED;
@@ -239,7 +243,7 @@ SusPayCreate::doApply()
(*sle)[sfBalance] = (*sle)[sfBalance] - ctx_.tx[sfAmount]; (*sle)[sfBalance] = (*sle)[sfBalance] - ctx_.tx[sfAmount];
(*sle)[sfOwnerCount] = (*sle)[sfOwnerCount] + 1; (*sle)[sfOwnerCount] = (*sle)[sfOwnerCount] + 1;
ctx_.view().update(sle); ctx_.view().update(sle);
return tesSUCCESS; return tesSUCCESS;
} }
@@ -253,6 +257,10 @@ SusPayFinish::preflight (PreflightContext const& ctx)
ctx.config.features)) ctx.config.features))
return temDISABLED; return temDISABLED;
auto const ret = preflight1 (ctx);
if (!isTesSuccess (ret))
return ret;
if (ctx.tx[~sfMethod]) if (ctx.tx[~sfMethod])
{ {
// Condition // Condition
@@ -291,7 +299,7 @@ SusPayFinish::preflight (PreflightContext const& ctx)
return temMALFORMED; return temMALFORMED;
} }
return Transactor::preflight(ctx); return preflight2 (ctx);
} }
TER TER
@@ -362,7 +370,11 @@ SusPayCancel::preflight (PreflightContext const& ctx)
ctx.config.features)) ctx.config.features))
return temDISABLED; return temDISABLED;
return Transactor::preflight(ctx); auto const ret = preflight1 (ctx);
if (!isTesSuccess (ret))
return ret;
return preflight2 (ctx);
} }
TER TER

View File

@@ -30,30 +30,42 @@
namespace ripple { namespace ripple {
/** Performs early sanity checks on the account and fee fields */
TER TER
Transactor::preflight (PreflightContext const& ctx) preflight1 (PreflightContext const& ctx)
{ {
auto& tx = ctx.tx; auto const id = ctx.tx.getAccountID(sfAccount);
auto& j = ctx.j;
auto const id = tx.getAccountID(sfAccount);
if (id == zero) if (id == zero)
{ {
JLOG(j.warning) << "Transactor::preflight: bad account id"; JLOG(ctx.j.warning) << "preflight1: bad account id";
return temBAD_SRC_ACCOUNT; return temBAD_SRC_ACCOUNT;
} }
// No point in going any further if the transaction fee is malformed.
auto const fee = ctx.tx.getTransactionFee ();
if (!fee.native () || fee < beast::zero || !isLegalNet (fee))
{
JLOG(ctx.j.debug) << "preflight1: invalid fee";
return temBAD_FEE;
}
return tesSUCCESS;
}
/** Checks whether the signature appears valid */
TER
preflight2 (PreflightContext const& ctx)
{
// Extract signing key // Extract signing key
// Transactions contain a signing key. This allows us to trivially verify a // Transactions contain a signing key. This allows us to trivially verify a
// transaction has at least been properly signed without going to disk. // transaction has at least been properly signed without going to disk.
// Each transaction also notes a source account id. This is used to verify // Each transaction also notes a source account id. This is used to verify
// that the signing key is associated with the account. // that the signing key is associated with the account.
// XXX This could be a lot cleaner to prevent unnecessary copying. // XXX This could be a lot cleaner to prevent unnecessary copying.
auto const pk = auto const pk = RippleAddress::createAccountPublic(
RippleAddress::createAccountPublic( ctx.tx.getSigningPubKey());
tx.getSigningPubKey());
if(! ctx.verify(tx, if(! ctx.verify(ctx.tx,
[&, ctx] (STTx const& tx) [&, ctx] (STTx const& tx)
{ {
return (ctx.flags & tapNO_CHECK_SIGN) || return (ctx.flags & tapNO_CHECK_SIGN) ||
@@ -66,7 +78,7 @@ Transactor::preflight (PreflightContext const& ctx)
); );
})) }))
{ {
JLOG(j.debug) << "apply: Invalid transaction (bad signature)"; JLOG(ctx.j.debug) << "preflight2: bad signature";
return temINVALID; return temINVALID;
} }
@@ -202,12 +214,6 @@ void Transactor::preCompute ()
TER Transactor::apply () TER Transactor::apply ()
{ {
// No point in going any further if the transaction fee is malformed.
STAmount const saTxnFee = tx().getTransactionFee ();
if (!saTxnFee.native () || saTxnFee.negative () || !isLegalNet (saTxnFee))
return temBAD_FEE;
preCompute(); preCompute();
// Find source account // Find source account

View File

@@ -87,10 +87,6 @@ public:
return ctx_.tx; return ctx_.tx;
} }
static
TER
preflight (PreflightContext const& ctx);
protected: protected:
TER TER
apply(); apply();
@@ -124,6 +120,14 @@ private:
TER checkMultiSign (); TER checkMultiSign ();
}; };
/** Performs early sanity checks on the account and fee fields */
TER
preflight1 (PreflightContext const& ctx);
/** Checks whether the signature appears valid */
TER
preflight2 (PreflightContext const& ctx);
} }
#endif #endif