diff --git a/src/ripple/app/tx/impl/TransactionEngine.cpp b/src/ripple/app/tx/impl/TransactionEngine.cpp index 0e2a2246b..377d87a4d 100644 --- a/src/ripple/app/tx/impl/TransactionEngine.cpp +++ b/src/ripple/app/tx/impl/TransactionEngine.cpp @@ -241,8 +241,17 @@ TransactionEngine::applyTransaction ( throw std::runtime_error ("Duplicate transaction applied to closed ledger"); } - // Charge whatever fee they specified. - mLedger->destroyCoins (getNValue (txn.getTransactionFee ())); + // Charge whatever fee they specified. We break the encapsulation of + // STAmount here and use "special knowledge" - namely that a native + // amount is stored fully in the mantissa: + auto const fee = txn.getTransactionFee (); + + // The transactor guarantees these will never trigger + if (!fee.native () || fee.negative ()) + throw std::runtime_error ("amount is negative!"); + + if (fee != zero) + mLedger->destroyCoins (fee.mantissa ()); } } diff --git a/src/ripple/app/tx/impl/Transactor.cpp b/src/ripple/app/tx/impl/Transactor.cpp index 409965913..976d54155 100644 --- a/src/ripple/app/tx/impl/Transactor.cpp +++ b/src/ripple/app/tx/impl/Transactor.cpp @@ -249,7 +249,13 @@ TER Transactor::preCheckSigningKey () TER Transactor::apply () { - TER terResult (preCheck ()); + // No point in going any further if the transaction fee is malformed. + STAmount const saTxnFee = mTxn.getTransactionFee (); + + if (!saTxnFee.native () || saTxnFee.negative () || !isLegalNet (saTxnFee)) + return temBAD_FEE; + + TER terResult = preCheck (); if (terResult != tesSUCCESS) return terResult;