Use XRPAmount for fees and ledger headers

This commit is contained in:
Nik Bougalis
2015-08-22 01:13:29 -07:00
parent 94af42da44
commit acd03faee5
27 changed files with 141 additions and 141 deletions

View File

@@ -359,7 +359,7 @@ void Ledger::updateHash()
info_.hash = sha512Half(
HashPrefix::ledgerMaster,
std::uint32_t(info_.seq),
std::uint64_t(info_.drops),
std::uint64_t(info_.drops.drops ()),
info_.parentHash,
info_.txHash,
info_.accountHash,
@@ -570,7 +570,7 @@ bool Ledger::saveValidatedLedger (bool current)
*db << boost::str (
addLedger %
to_string (getHash ()) % info_.seq % to_string (info_.parentHash) %
std::to_string (info_.drops) % info_.closeTime %
to_string (info_.drops) % info_.closeTime %
info_.parentCloseTime % info_.closeTimeResolution %
info_.closeFlags % to_string (info_.accountHash) %
to_string (info_.txHash));

View File

@@ -200,9 +200,9 @@ public:
SLE> const& sle) override;
void
rawDestroyXRP (std::uint64_t feeDrops) override
rawDestroyXRP (XRPAmount const& fee) override
{
info_.drops -= feeDrops;
info_.drops -= fee;
}
//

View File

@@ -23,6 +23,7 @@
#include <ripple/ledger/ApplyViewImpl.h>
#include <ripple/core/Config.h>
#include <ripple/protocol/STTx.h>
#include <ripple/protocol/XRPAmount.h>
#include <beast/utility/Journal.h>
#include <boost/optional.hpp>
#include <utility>
@@ -92,9 +93,9 @@ public:
std::shared_ptr <SLE const> const& after)> const& func);
void
destroyXRP (std::uint64_t feeDrops)
destroyXRP (XRPAmount const& fee)
{
view_->rawDestroyXRP(feeDrops);
view_->rawDestroyXRP(fee);
}
private:

View File

@@ -38,10 +38,11 @@ Change::preflight (PreflightContext const& ctx)
return temBAD_SRC_ACCOUNT;
}
auto const fee = ctx.tx.getTransactionFee ();
// No point in going any further if the transaction fee is malformed.
auto const fee = ctx.tx.getFieldAmount (sfFee);
if (!fee.native () || fee != beast::zero)
{
JLOG(ctx.j.warning) << "Change: Non-zero fee";
JLOG(ctx.j.warning) << "Change: invalid fee";
return temBAD_FEE;
}

View File

@@ -539,20 +539,6 @@ CreateOffer::format_amount (STAmount const& amount)
return txt;
}
STAmount
CreateOffer::getAccountReserve (SLE::pointer account)
{
// Mon Aug 17 11:00:00am PDT
static NetClock::time_point const switchoverTime (
std::chrono::seconds (493149600));
if (ctx_.view().info().parentCloseTime <=
switchoverTime.time_since_epoch().count())
return STAmount (ctx_.view().fees().accountReserve(
deprecatedWrongOwnerCount_+1));
return STAmount (ctx_.view().fees().accountReserve(
account->getFieldU32 (sfOwnerCount) + 1));
}
void
CreateOffer::preCompute()
{
@@ -784,18 +770,34 @@ CreateOffer::applyGuts (ApplyView& view, ApplyView& view_cancel)
return { tesSUCCESS, true };
}
if (mPriorBalance < getAccountReserve (sleCreator))
{
// If we are here, the signing account had an insufficient reserve
// *prior* to our processing. If something actually crossed, then
// we allow this; otherwise, we just claim a fee.
if (!crossed)
result = tecINSUF_RESERVE_OFFER;
// Mon Aug 17 11:00:00am PDT
static NetClock::time_point const switchoverTime (
std::chrono::seconds (493149600));
if (result != tesSUCCESS)
j_.debug << "final result: " << transToken (result);
XRPAmount reserve;
return { result, true };
if (ctx_.view().info().parentCloseTime <=
switchoverTime.time_since_epoch().count())
reserve = ctx_.view().fees().accountReserve(
deprecatedWrongOwnerCount_+1);
else
reserve = ctx_.view().fees().accountReserve(
sleCreator->getFieldU32 (sfOwnerCount) + 1);
if (mPriorBalance < reserve)
{
// If we are here, the signing account had an insufficient reserve
// *prior* to our processing. If something actually crossed, then
// we allow this; otherwise, we just claim a fee.
if (!crossed)
result = tecINSUF_RESERVE_OFFER;
if (result != tesSUCCESS)
j_.debug << "final result: " << transToken (result);
return { result, true };
}
}
// We need to place the remainder of the offer into its order book.

View File

@@ -49,11 +49,6 @@ public:
TER
preflight (PreflightContext const& ctx);
/** Returns the reserve the account would have if an offer was added. */
// VFALCO This function is not needed just inline the behavior
STAmount
getAccountReserve (SLE::pointer account); // const?
void
preCompute() override;

View File

@@ -50,22 +50,21 @@ CreateTicket::preflight (PreflightContext const& ctx)
return preflight2 (ctx);
}
STAmount
CreateTicket::getAccountReserve (SLE::pointer account)
{
return STAmount (view().fees().accountReserve(
account->getFieldU32 (sfOwnerCount) + 1));
}
TER
CreateTicket::doApply ()
{
auto const sle = view().peek(keylet::account(account_));
// A ticket counts against the reserve of the issuing account, but we
// check the starting balance because we want to allow dipping into the
// reserve to pay fees.
if (mPriorBalance < STAmount(view().fees().accountReserve(
view().read(keylet::account(account_))->getFieldU32(sfOwnerCount) + 1)))
return tecINSUFFICIENT_RESERVE;
{
auto const reserve = view().fees().accountReserve(
sle->getFieldU32(sfOwnerCount) + 1);
if (mPriorBalance < reserve)
return tecINSUFFICIENT_RESERVE;
}
std::uint32_t expiration (0);
@@ -124,8 +123,7 @@ CreateTicket::doApply ()
sleTicket->setFieldU64(sfOwnerNode, hint);
// If we succeeded, the new entry counts agains the creator's reserve.
adjustOwnerCount(view(), view().peek(
keylet::account(account_)), 1);
adjustOwnerCount(view(), sle, 1);
return result;
}

View File

@@ -40,11 +40,6 @@ public:
TER
preflight (PreflightContext const& ctx);
/** Returns the reserve the account would have if an offer was added. */
// VFALCO Not needed, just inline the behavior.
STAmount
getAccountReserve (SLE::pointer account);
TER doApply () override;
};

View File

@@ -380,6 +380,8 @@ Payment::doApply ()
}
else
{
assert (saDstAmount.native ());
// Direct XRP payment.
// uOwnerCount is the number of entries in this legder for this
@@ -388,23 +390,22 @@ Payment::doApply ()
keylet::account(account_))->getFieldU32 (sfOwnerCount);
// This is the total reserve in drops.
auto const uReserve =
view().fees().accountReserve(uOwnerCount);
auto const reserve = view().fees().accountReserve(uOwnerCount);
// mPriorBalance is the balance on the sending account BEFORE the
// fees were charged. We want to make sure we have enough reserve
// to send. Allow final spend to use reserve for fee.
auto const mmm = std::max(tx().getTransactionFee (),
STAmount (uReserve));
auto const mmm = std::max(reserve,
tx().getFieldAmount (sfFee).xrp ());
if (mPriorBalance < saDstAmount + mmm)
if (mPriorBalance < saDstAmount.xrp () + mmm)
{
// Vote no. However the transaction might succeed, if applied in
// a different order.
j_.trace << "Delay transaction: Insufficient funds: " <<
" " << mPriorBalance.getText () <<
" / " << (saDstAmount + mmm).getText () <<
" (" << uReserve << ")";
" " << to_string (mPriorBalance) <<
" / " << to_string (saDstAmount.xrp () + mmm) <<
" (" << to_string (reserve) << ")";
terResult = tecUNFUNDED_PAYMENT;
}

View File

@@ -119,8 +119,8 @@ SetTrust::doApply ()
// to fund accounts in a way where there's no incentive to trick them
// into creating an account you have no intention of using.
STAmount const reserveCreate ((uOwnerCount < 2)
? 0
XRPAmount const reserveCreate ((uOwnerCount < 2)
? XRPAmount (zero)
: view().fees().accountReserve(uOwnerCount + 1));
std::uint32_t uQualityIn (bQualityIn ? tx().getFieldU32 (sfQualityIn) : 0);

View File

@@ -183,23 +183,22 @@ SusPayCreate::doApply()
return tecNO_PERMISSION;
}
XRPAmount const amount =
STAmount(ctx_.tx[sfAmount]).mantissa();
auto const account = ctx_.tx[sfAccount];
auto const sle = ctx_.view().peek(
keylet::account(account));
if (XRPAmount(STAmount((*sle)[sfBalance]).mantissa()) <
XRPAmount(ctx_.view().fees().accountReserve(
(*sle)[sfOwnerCount] + 1)))
return tecINSUFFICIENT_RESERVE;
// Check reserve and funds availability
{
auto const balance = STAmount((*sle)[sfBalance]).xrp();
auto const reserve = ctx_.view().fees().accountReserve(
(*sle)[sfOwnerCount] + 1);
if (XRPAmount(STAmount((*sle)[sfBalance]).mantissa()) <
amount + XRPAmount(ctx_.view().fees().accountReserve(
(*sle)[sfOwnerCount] + 1)))
return tecUNFUNDED;
if (balance < reserve)
return tecINSUFFICIENT_RESERVE;
if (balance < reserve + STAmount(ctx_.tx[sfAmount]).xrp())
return tecUNFUNDED;
}
// Check destination account
{

View File

@@ -44,8 +44,8 @@ preflight1 (PreflightContext const& ctx)
}
// 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))
auto const fee = ctx.tx.getFieldAmount (sfFee);
if (!fee.native () || fee.negative () || !isLegalAmount (fee.xrp ()))
{
JLOG(ctx.j.debug) << "preflight1: invalid fee";
return temBAD_FEE;
@@ -114,30 +114,29 @@ std::uint64_t Transactor::calculateBaseFee ()
TER Transactor::payFee ()
{
STAmount saPaid = tx().getTransactionFee ();
if (!isLegalNet (saPaid) || saPaid < zero)
auto const feePaid = tx().getFieldAmount (sfFee).xrp ();
if (!isLegalAmount (feePaid) || feePaid < beast::zero)
return temBAD_FEE;
// Only check fee is sufficient when the ledger is open.
if (view().open() && saPaid < mFeeDue)
if (view().open() && feePaid < mFeeDue)
{
JLOG(j_.trace) << "Insufficient fee paid: " <<
saPaid.getText () << "/" << mFeeDue.getText ();
to_string (feePaid) << "/" << to_string (mFeeDue);
return telINSUF_FEE_P;
}
if (saPaid == zero)
if (feePaid == zero)
return tesSUCCESS;
auto const sle = view().peek(
keylet::account(account_));
if (mSourceBalance < saPaid)
if (mSourceBalance < feePaid)
{
JLOG(j_.trace) << "Insufficient balance:" <<
" balance=" << mSourceBalance.getText () <<
" paid=" << saPaid.getText ();
" balance=" << to_string (mSourceBalance) <<
" paid=" << to_string (feePaid);
if ((mSourceBalance > zero) && ! view().open())
{
@@ -151,7 +150,7 @@ TER Transactor::payFee ()
// Deduct the fee, so it's not available during the transaction.
// Will only write the account back, if the transaction succeeds.
mSourceBalance -= saPaid;
mSourceBalance -= feePaid;
sle->setFieldAmount (sfBalance, mSourceBalance);
// VFALCO Should we call view().rawDestroyXRP() here as well?
@@ -227,12 +226,12 @@ TER Transactor::apply ()
}
auto const& fees = view().fees();
mFeeDue = STAmount (getApp().getFeeTrack().scaleFeeLoad(
calculateBaseFee(), fees.base, fees.units, view().flags() & tapADMIN));
mFeeDue = getApp().getFeeTrack().scaleFeeLoad(
calculateBaseFee(), fees.base, fees.units, view().flags() & tapADMIN);
if (sle)
{
mPriorBalance = sle->getFieldAmount (sfBalance);
mPriorBalance = STAmount ((*sle)[sfBalance]).xrp ();
mSourceBalance = mPriorBalance;
mHasAuthKey = sle->isFieldPresent (sfRegularKey);
@@ -550,7 +549,7 @@ Transactor::operator()()
}
bool didApply = isTesSuccess (terResult);
auto fee = tx().getTransactionFee ();
auto fee = tx().getFieldAmount(sfFee).xrp ();
if (ctx_.size() > 5200)
terResult = tecOVERSIZE;
@@ -602,7 +601,7 @@ Transactor::operator()()
terResult = tefPAST_SEQ;
else
{
STAmount balance = txnAcct->getFieldAmount (sfBalance);
auto const balance = txnAcct->getFieldAmount (sfBalance).xrp ();
// We retry/reject the transaction if the account
// balance is zero or we're applying against an open
@@ -645,23 +644,18 @@ Transactor::operator()()
if(view().closed())
{
// VFALCO Fix this nonsense with Amount
// 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:
// Charge whatever fee they specified.
// The transactor guarantees these will never trigger
if (!fee.native () || fee.negative ())
// The transactor guarantees this will never trigger
if (fee < zero)
{
// VFALCO Log to journal here
// JLOG(journal.fatal) << "invalid fee";
throw std::logic_error(
"amount is negative!");
throw std::logic_error("amount is negative!");
}
if (fee != zero)
ctx_.destroyXRP (fee.mantissa ());
ctx_.destroyXRP (fee);
}
ctx_.apply(terResult);

View File

@@ -21,6 +21,7 @@
#define RIPPLE_APP_TX_TRANSACTOR_H_INCLUDED
#include <ripple/app/tx/impl/ApplyContext.h>
#include <ripple/protocol/XRPAmount.h>
#include <beast/utility/Journal.h>
namespace ripple {
@@ -57,9 +58,9 @@ protected:
beast::Journal j_;
AccountID account_;
STAmount mFeeDue;
STAmount mPriorBalance; // Balance before fees.
STAmount mSourceBalance; // Balance after fees.
XRPAmount mFeeDue;
XRPAmount mPriorBalance; // Balance before fees.
XRPAmount mSourceBalance; // Balance after fees.
bool mHasAuthKey;
bool mSigMaster;
RippleAddress mSigningPubKey;

View File

@@ -23,6 +23,7 @@
#include <ripple/ledger/RawView.h>
#include <ripple/ledger/ReadView.h>
#include <ripple/ledger/detail/RawStateTable.h>
#include <ripple/protocol/XRPAmount.h>
namespace ripple {
@@ -209,7 +210,7 @@ public:
void
rawDestroyXRP(
std::uint64_t feeDrops) override;
XRPAmount const& fee) override;
// TxsRawView

View File

@@ -85,7 +85,7 @@ public:
*/
virtual
void
rawDestroyXRP (std::uint64_t feeDrops) = 0;
rawDestroyXRP (XRPAmount const& fee) = 0;
};
//------------------------------------------------------------------------------

View File

@@ -23,9 +23,11 @@
#include <ripple/ledger/detail/ReadViewFwdRange.h>
#include <ripple/basics/chrono.h>
#include <ripple/protocol/Indexes.h>
#include <ripple/protocol/IOUAmount.h>
#include <ripple/protocol/Protocol.h>
#include <ripple/protocol/STLedgerEntry.h>
#include <ripple/protocol/STTx.h>
#include <ripple/protocol/XRPAmount.h>
#include <beast/hash/uhash.h>
#include <boost/optional.hpp>
#include <cassert>
@@ -56,10 +58,10 @@ struct Fees
The reserve is calculated as the reserve base plus
the reserve increment times the number of increments.
*/
std::uint64_t
XRPAmount
accountReserve (std::size_t ownerCount) const
{
return reserve + ownerCount * increment;
return { reserve + ownerCount * increment };
}
};
@@ -85,7 +87,8 @@ struct LedgerInfo
uint256 txHash = zero;
uint256 accountHash = zero;
uint256 parentHash = zero;
std::uint64_t drops = 0;
XRPAmount drops = zero;
// If validated is false, it means "not yet validated."
// Once validated is true, it will never be set false at a later time.

View File

@@ -25,6 +25,7 @@
#include <ripple/ledger/ReadView.h>
#include <ripple/ledger/TxMeta.h>
#include <ripple/protocol/TER.h>
#include <ripple/protocol/XRPAmount.h>
#include <beast/utility/Journal.h>
#include <memory>
@@ -50,7 +51,7 @@ private:
std::pair<Action, std::shared_ptr<SLE>>>;
items_t items_;
std::uint64_t dropsDestroyed_ = 0;
XRPAmount dropsDestroyed_ = 0;
public:
ApplyStateTable() = default;
@@ -126,7 +127,7 @@ public:
std::shared_ptr<SLE> const& sle);
void
destroyXRP (std::uint64_t feeDrops);
destroyXRP (XRPAmount const& fee);
private:
using Mods = hash_map<key_type,

View File

@@ -24,6 +24,7 @@
#include <ripple/ledger/OpenView.h>
#include <ripple/ledger/ReadView.h>
#include <ripple/ledger/detail/ApplyStateTable.h>
#include <ripple/protocol/XRPAmount.h>
namespace ripple {
namespace detail {
@@ -130,13 +131,13 @@ public:
void
rawDestroyXRP (
std::uint64_t feeDrops) override;
XRPAmount const& feeDrops) override;
protected:
ApplyFlags flags_;
ReadView const* base_;
detail::ApplyStateTable items_;
std::uint64_t dropsDestroyed_ = 0;
XRPAmount dropsDestroyed_ = 0;
};
} // detail

View File

@@ -75,7 +75,7 @@ public:
Keylet const& k) const;
void
destroyXRP (std::uint64_t feeDrops);
destroyXRP (XRPAmount const& fee);
std::unique_ptr<ReadView::sles_type::iter_base>
slesBegin (ReadView const& base) const;
@@ -97,7 +97,7 @@ private:
std::pair<Action, std::shared_ptr<SLE>>>;
items_t items_;
std::uint64_t dropsDestroyed_ = 0;
XRPAmount dropsDestroyed_ = 0;
};
} // detail

View File

@@ -521,9 +521,9 @@ ApplyStateTable::update (ReadView const& base,
}
void
ApplyStateTable::destroyXRP(std::uint64_t feeDrops)
ApplyStateTable::destroyXRP(XRPAmount const& fee)
{
dropsDestroyed_ += feeDrops;
dropsDestroyed_ += fee;
}
//------------------------------------------------------------------------------

View File

@@ -173,9 +173,9 @@ ApplyViewBase::rawReplace(
void
ApplyViewBase::rawDestroyXRP(
std::uint64_t feeDrops)
XRPAmount const& fee)
{
items_.destroyXRP(feeDrops);
items_.destroyXRP(fee);
}
} // detail

View File

@@ -247,9 +247,9 @@ OpenView::rawReplace(
void
OpenView::rawDestroyXRP(
std::uint64_t feeDrops)
XRPAmount const& fee)
{
items_.destroyXRP(feeDrops);
items_.destroyXRP(fee);
// VFALCO Deduct from info_.totalDrops ?
// What about child views?
}

View File

@@ -333,9 +333,9 @@ RawStateTable::read (ReadView const& base,
}
void
RawStateTable::destroyXRP(std::uint64_t feeDrops)
RawStateTable::destroyXRP(XRPAmount const& fee)
{
dropsDestroyed_ += feeDrops;
dropsDestroyed_ += fee;
}
std::unique_ptr<ReadView::sles_type::iter_base>

View File

@@ -47,7 +47,7 @@ namespace ripple {
void addRaw (LedgerInfo const& info, Serializer& s)
{
s.add32 (info.seq);
s.add64 (info.drops);
s.add64 (info.drops.drops ());
s.add256 (info.parentHash);
s.add256 (info.txHash);
s.add256 (info.accountHash);
@@ -109,10 +109,10 @@ accountHolds (ReadView const& view,
auto const sle = view.read(
keylet::account(account));
auto const reserve =
STAmount{view.fees().accountReserve(
sle->getFieldU32(sfOwnerCount))};
view.fees().accountReserve(
sle->getFieldU32(sfOwnerCount));
auto const balance =
sle->getFieldAmount(sfBalance);
sle->getFieldAmount(sfBalance).xrp ();
if (balance < reserve)
amount.clear ();
else
@@ -120,8 +120,8 @@ accountHolds (ReadView const& view,
WriteLog (lsTRACE, View) << "accountHolds:" <<
" account=" << to_string (account) <<
" amount=" << amount.getFullText () <<
" balance=" << balance.getFullText () <<
" reserve=" << reserve.getFullText ();
" balance=" << to_string (balance) <<
" reserve=" << to_string (reserve);
}
else
{

View File

@@ -203,6 +203,12 @@ public:
return *this;
}
STAmount& operator= (XRPAmount const& amount)
{
*this = STAmount (amount);
return *this;
}
//--------------------------------------------------------------------------
//
// Modification

View File

@@ -88,14 +88,6 @@ public:
{
return tx_type_;
}
STAmount getTransactionFee () const
{
return getFieldAmount (sfFee);
}
void setTransactionFee (const STAmount & fee)
{
setFieldAmount (sfFee, fee);
}
Blob getSigningPubKey () const
{

View File

@@ -1087,12 +1087,21 @@ Json::Value transactionSubmitMultiSigned (
return RPC::make_error (rpcINVALID_PARAMS, err.str ());
}
// The Fee field must be greater than zero.
if (stpTrans->getFieldAmount (sfFee) <= 0)
// The Fee field must be in XRP and greater than zero.
auto const fee = stpTrans->getFieldAmount (sfFee);
if (!isLegalNet (fee))
{
std::ostringstream err;
err << "Invalid " << sfFee.fieldName
<< " field. Value must be greater than zero.";
<< " field. Fees must be specified in XRP.";
return RPC::make_error (rpcINVALID_PARAMS, err.str ());
}
if (fee <= 0)
{
std::ostringstream err;
err << "Invalid " << sfFee.fieldName
<< " field. Fees must be greater than zero.";
return RPC::make_error (rpcINVALID_PARAMS, err.str ());
}
}