Improve version switchover semantics:

* Support PreviousTxnID until the switchover
* Implement "No Ripple" for issue_iou and redeem_iou.
* Do not utilize issue_iou and redeem_iou from legacy code
* Rename 0.27.x legacy files to account for VS build process
* Misc. cleanups
This commit is contained in:
Nik Bougalis
2015-03-22 14:34:34 -07:00
parent 091ff0cce0
commit a7efdb4e52
17 changed files with 147 additions and 127 deletions

View File

@@ -2442,19 +2442,19 @@
</ClInclude>
<ClInclude Include="..\..\src\ripple\legacy\0.27\book\BookTip.h">
</ClInclude>
<ClCompile Include="..\..\src\ripple\legacy\0.27\book\impl\BookTip.cpp">
<ClCompile Include="..\..\src\ripple\legacy\0.27\book\impl\BookTip27.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\src\ripple\legacy\0.27\book\impl\OfferStream.cpp">
<ClCompile Include="..\..\src\ripple\legacy\0.27\book\impl\OfferStream27.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\src\ripple\legacy\0.27\book\impl\Quality.cpp">
<ClCompile Include="..\..\src\ripple\legacy\0.27\book\impl\Quality27.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\src\ripple\legacy\0.27\book\impl\Taker.cpp">
<ClCompile Include="..\..\src\ripple\legacy\0.27\book\impl\Taker27.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
</ClCompile>
@@ -2468,12 +2468,12 @@
</ClInclude>
<ClInclude Include="..\..\src\ripple\legacy\0.27\book\Types.h">
</ClInclude>
<ClCompile Include="..\..\src\ripple\legacy\0.27\CreateOffer.cpp">
<ClInclude Include="..\..\src\ripple\legacy\0.27\CreateOffer.h">
</ClInclude>
<ClCompile Include="..\..\src\ripple\legacy\0.27\CreateOffer27.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
</ClCompile>
<ClInclude Include="..\..\src\ripple\legacy\0.27\CreateOffer.h">
</ClInclude>
<ClCompile Include="..\..\src\ripple\legacy\0.27\Emulate027.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
@@ -4496,8 +4496,6 @@
</ClCompile>
<ClInclude Include="..\..\src\soci\src\core\values.h">
</ClInclude>
<ClInclude Include="..\..\src\soci\src\core\version.h">
</ClInclude>
<ClInclude Include="..\..\src\sqlite\sqlite.h">
</ClInclude>
<ClCompile Include="..\..\src\sqlite\sqlite.unity.c">

View File

@@ -3003,16 +3003,16 @@
<ClInclude Include="..\..\src\ripple\legacy\0.27\book\BookTip.h">
<Filter>ripple\legacy\0.27\book</Filter>
</ClInclude>
<ClCompile Include="..\..\src\ripple\legacy\0.27\book\impl\BookTip.cpp">
<ClCompile Include="..\..\src\ripple\legacy\0.27\book\impl\BookTip27.cpp">
<Filter>ripple\legacy\0.27\book\impl</Filter>
</ClCompile>
<ClCompile Include="..\..\src\ripple\legacy\0.27\book\impl\OfferStream.cpp">
<ClCompile Include="..\..\src\ripple\legacy\0.27\book\impl\OfferStream27.cpp">
<Filter>ripple\legacy\0.27\book\impl</Filter>
</ClCompile>
<ClCompile Include="..\..\src\ripple\legacy\0.27\book\impl\Quality.cpp">
<ClCompile Include="..\..\src\ripple\legacy\0.27\book\impl\Quality27.cpp">
<Filter>ripple\legacy\0.27\book\impl</Filter>
</ClCompile>
<ClCompile Include="..\..\src\ripple\legacy\0.27\book\impl\Taker.cpp">
<ClCompile Include="..\..\src\ripple\legacy\0.27\book\impl\Taker27.cpp">
<Filter>ripple\legacy\0.27\book\impl</Filter>
</ClCompile>
<ClInclude Include="..\..\src\ripple\legacy\0.27\book\Offer.h">
@@ -3030,12 +3030,12 @@
<ClInclude Include="..\..\src\ripple\legacy\0.27\book\Types.h">
<Filter>ripple\legacy\0.27\book</Filter>
</ClInclude>
<ClCompile Include="..\..\src\ripple\legacy\0.27\CreateOffer.cpp">
<Filter>ripple\legacy\0.27</Filter>
</ClCompile>
<ClInclude Include="..\..\src\ripple\legacy\0.27\CreateOffer.h">
<Filter>ripple\legacy\0.27</Filter>
</ClInclude>
<ClCompile Include="..\..\src\ripple\legacy\0.27\CreateOffer27.cpp">
<Filter>ripple\legacy\0.27</Filter>
</ClCompile>
<ClCompile Include="..\..\src\ripple\legacy\0.27\Emulate027.cpp">
<Filter>ripple\legacy\0.27</Filter>
</ClCompile>
@@ -5268,9 +5268,6 @@
<ClInclude Include="..\..\src\soci\src\core\values.h">
<Filter>soci\src\core</Filter>
</ClInclude>
<ClInclude Include="..\..\src\soci\src\core\version.h">
<Filter>soci\src\core</Filter>
</ClInclude>
<ClInclude Include="..\..\src\sqlite\sqlite.h">
<Filter>sqlite</Filter>
</ClInclude>

View File

@@ -180,13 +180,6 @@
#define RIPPLE_PROPOSE_AMENDMENTS 0
#endif
/** Config: RIPPLE_ENABLE_AUTOBRIDGING
This determines whether ripple implements offer autobridging via XRP.
*/
#ifndef RIPPLE_ENABLE_AUTOBRIDGING
#define RIPPLE_ENABLE_AUTOBRIDGING 1
#endif
/** Config: RIPPLE_SINGLE_IO_SERVICE_THREAD
When set, restricts the number of threads calling io_service::run to one.
This is useful when debugging.

View File

@@ -1547,6 +1547,33 @@ TER LedgerEntrySet::rippleCredit (
return terResult;
}
// Calculate the fee needed to transfer IOU assets between two parties.
STAmount LedgerEntrySet::rippleTransferFee (
Account const& from,
Account const& to,
Account const& issuer,
STAmount const& saAmount)
{
if (from != issuer && to != issuer)
{
std::uint32_t uTransitRate = rippleTransferRate (*this, issuer);
if (QUALITY_ONE != uTransitRate)
{
STAmount saTransferTotal = multiply (
saAmount, amountFromRate (uTransitRate), saAmount.issue ());
STAmount saTransferFee = saTransferTotal - saAmount;
WriteLog (lsDEBUG, LedgerEntrySet) << "rippleTransferFee:" <<
" saTransferFee=" << saTransferFee.getFullText ();
return saTransferFee;
}
}
return saAmount.zeroed();
}
// Send regardless of limits.
// --> saAmount: Amount/currency/issuer to deliver to reciever.
// <-- saActual: Amount actually cost. Sender pay's fees.
@@ -1554,72 +1581,43 @@ TER LedgerEntrySet::rippleSend (
Account const& uSenderID, Account const& uReceiverID,
STAmount const& saAmount, STAmount& saActual)
{
auto const& issue = saAmount.issue ();
auto const& issuer = saAmount.issue ().account;
auto const issuer = saAmount.getIssuer ();
TER terResult;
assert (!isXRP (uSenderID) && !isXRP (uReceiverID));
assert (uSenderID != uReceiverID);
// Issues and redeems are processed directly without any fees.
if (uSenderID == issue.account)
if (uSenderID == issuer || uReceiverID == issuer || issuer == noAccount())
{
assert (issue.account != noAccount ());
saActual = saAmount;
return issue_iou (uReceiverID, saAmount, issue);
}
if (uReceiverID == issue.account)
{
assert (issue.account != noAccount ());
saActual = saAmount;
return redeem_iou (uSenderID, saAmount, issue);
}
// NIKB TODO: What is going on here? Under what circumstances would we try
// to transfer some currency without a specified issuer?
if (issue.account == noAccount())
{
WriteLog (lsDEBUG, LedgerEntrySet) <<
"rippleSend> " << to_string (uSenderID) <<
" - > " << to_string (uReceiverID) <<
" : amount with issuer=1: " << saAmount.getFullText ();
// Direct send: redeeming IOUs and/or sending own IOUs.
TER result = rippleCredit (uSenderID, uReceiverID, saAmount, false);
saActual = saAmount;
// NIKB CHECKME: Why are we setting terResult to tesSUCCESS here?
result = tesSUCCESS;
return result;
terResult = rippleCredit (uSenderID, uReceiverID, saAmount, false);
saActual = saAmount;
terResult = tesSUCCESS;
}
assert (uSenderID != issue.account && uReceiverID != issue.account);
// Sending IOUs to a third party: we must calculate the transit fee, by
// applying the transfer rate, if any.
saActual = saAmount;
std::uint32_t const transit_rate = rippleTransferRate (*this, issuer);
if (QUALITY_ONE != transit_rate)
else
{
saActual = multiply (saActual, amountFromRate (transit_rate),
saActual.issue ());
// Sending 3rd party IOUs: transit.
STAmount saTransitFee = rippleTransferFee (
uSenderID, uReceiverID, issuer, saAmount);
saActual = !saTransitFee ? saAmount : saAmount + saTransitFee;
saActual.setIssuer (issuer); // XXX Make sure this done in + above.
WriteLog (lsDEBUG, LedgerEntrySet) << "rippleSend> " <<
to_string (uSenderID) <<
" - > " << to_string (uReceiverID) <<
" : deliver=" << saAmount.getFullText () <<
" fee=" << saTransitFee.getFullText () <<
" cost=" << saActual.getFullText ();
terResult = rippleCredit (issuer, uReceiverID, saAmount);
if (tesSUCCESS == terResult)
terResult = rippleCredit (uSenderID, issuer, saActual);
}
WriteLog (lsDEBUG, LedgerEntrySet) <<
"rippleSend> " << to_string (uSenderID) <<
" - > " << to_string (uReceiverID) <<
" : deliver=" << saAmount.getFullText () <<
" cost=" << saActual.getFullText () <<
" fee=" << (saActual - saAmount).getFullText ();
TER terResult = issue_iou (uReceiverID, saAmount, saAmount.issue ());
if (tesSUCCESS == terResult)
terResult = redeem_iou (uSenderID, saActual, saActual.issue ());
return terResult;
}
@@ -1725,45 +1723,47 @@ TER LedgerEntrySet::accountSend (
bool LedgerEntrySet::checkState (
SLE::pointer state,
bool bIssuerHigh,
bool bSenderHigh,
Account const& sender,
STAmount const& before,
STAmount const& after)
{
std::uint32_t const flags (state->getFieldU32 (sfFlags));
auto sender_account = entryCache (ltACCOUNT_ROOT,
getAccountRootIndex (sender));
assert (sender_account);
// YYY Could skip this if rippling in reverse.
if (before > zero
// Sender balance was positive.
&& after <= zero
// Sender is zero or negative.
&& (flags & (!bIssuerHigh ? lsfLowReserve : lsfHighReserve))
&& (flags & (!bSenderHigh ? lsfLowReserve : lsfHighReserve))
// Sender reserve is set.
&& static_cast <bool> (flags & (!bIssuerHigh ? lsfLowNoRipple : lsfHighNoRipple)) !=
static_cast <bool> (entryCache (ltACCOUNT_ROOT,
getAccountRootIndex (sender))->getFlags() & lsfDefaultRipple)
&& !(flags & (!bIssuerHigh ? lsfLowFreeze : lsfHighFreeze))
&& static_cast <bool> (flags & (!bSenderHigh ? lsfLowNoRipple : lsfHighNoRipple)) !=
static_cast <bool> (sender_account->getFlags() & lsfDefaultRipple)
&& !(flags & (!bSenderHigh ? lsfLowFreeze : lsfHighFreeze))
&& !state->getFieldAmount (
!bIssuerHigh ? sfLowLimit : sfHighLimit)
!bSenderHigh ? sfLowLimit : sfHighLimit)
// Sender trust limit is 0.
&& !state->getFieldU32 (
!bIssuerHigh ? sfLowQualityIn : sfHighQualityIn)
!bSenderHigh ? sfLowQualityIn : sfHighQualityIn)
// Sender quality in is 0.
&& !state->getFieldU32 (
!bIssuerHigh ? sfLowQualityOut : sfHighQualityOut))
!bSenderHigh ? sfLowQualityOut : sfHighQualityOut))
// Sender quality out is 0.
{
// Clear the reserve of the sender, possibly delete the line!
decrementOwnerCount (sender);
decrementOwnerCount (sender_account);
// Clear reserve flag.
state->setFieldU32 (
sfFlags,
flags & (!bIssuerHigh ? ~lsfLowReserve : ~lsfHighReserve));
state->setFieldU32 (sfFlags,
flags & (!bSenderHigh ? ~lsfLowReserve : ~lsfHighReserve));
// Balance is zero, receiver reserve is clear.
if (!after // Balance is zero.
&& !(flags & (bIssuerHigh ? lsfLowReserve : lsfHighReserve)))
&& !(flags & (bSenderHigh ? lsfLowReserve : lsfHighReserve)))
return true;
}
@@ -1802,9 +1802,16 @@ TER LedgerEntrySet::issue_iou (
final_balance.setIssuer (noAccount());
SLE::pointer receiverAccount = entryCache (ltACCOUNT_ROOT,
getAccountRootIndex (account));
bool noRipple = (receiverAccount->getFlags() & lsfDefaultRipple) == 0;
if (ripple::legacy::emulate027 (mLedger))
noRipple = false;
return trustCreate (bSenderHigh, issue.account, account, index,
entryCache (ltACCOUNT_ROOT, getAccountRootIndex (account)),
false, false, false, final_balance, limit);
receiverAccount, false, noRipple, false, final_balance, limit);
}
STAmount final_balance = state->getFieldAmount (sfBalance);
@@ -1862,14 +1869,14 @@ TER LedgerEntrySet::redeem_iou (
if (!state)
{
STAmount limit(issue);
STAmount final_balance = amount;
// In order to hold an IOU, a trust line *MUST* exist to track the
// balance. If it doesn't, then something is very wrong. Don't try
// to continue.
WriteLog (lsFATAL, LedgerEntrySet) << "redeem_iou: " <<
to_string (account) << " attempts to redeem " <<
amount.getFullText () << " but no trust line exists!";
final_balance.setIssuer (noAccount());
return trustCreate (bSenderHigh, account, issue.account, index,
entryCache (ltACCOUNT_ROOT, getAccountRootIndex (issue.account)),
false, false, false, final_balance, limit);
return tefINTERNAL;
}
STAmount final_balance = state->getFieldAmount (sfBalance);

View File

@@ -332,7 +332,11 @@ private:
Account const& account, Currency const& currency,
Account const& issuer, FreezeHandling zeroIfFrozen);
bool checkState (SLE::pointer state, bool bIssuerHigh,
STAmount rippleTransferFee (
Account const& from, Account const& to,
Account const& issuer, STAmount const& saAmount);
bool checkState (SLE::pointer state, bool bSenderHigh,
Account const& sender, STAmount const& before, STAmount const& after);
};

View File

@@ -28,6 +28,7 @@
#include <ripple/json/to_string.h>
#include <ripple/legacy/0.27/CreateOffer.h>
#include <ripple/legacy/0.27/Emulate027.h>
#include <beast/cxx14/memory.h>
#include <stdexcept>
@@ -150,7 +151,7 @@ private:
{
auto const& taker_amount = taker.original_offer ();
assert (!isXRP (taker_amount.in)&& !isXRP (taker_amount.in));
assert (!isXRP (taker_amount.in) && !isXRP (taker_amount.out));
if (isXRP (taker_amount.in) || isXRP (taker_amount.out))
throw std::logic_error ("Bridging with XRP and an endpoint.");
@@ -385,7 +386,7 @@ private:
}
// Fill offer as much as possible by consuming offers already on the books,
// and adjusting account balances accordingly.
// and adjusting account balances accordingly.
//
// Charges fees on top to taker.
std::pair<TER, core::Amounts>
@@ -411,10 +412,8 @@ private:
m_journal.debug << " Balance: " << format_amount (funds);
}
#if RIPPLE_ENABLE_AUTOBRIDGING
if (cross_type_ == core::CrossType::IouToIou)
return bridged_cross (taker, view, cancel_view, when);
#endif
return direct_cross (taker, view, cancel_view, when);
}
@@ -641,7 +640,7 @@ public:
}
// Process a cancellation request that's passed along with an offer.
if ((result == tesSUCCESS) && bHaveCancel)
if (bHaveCancel)
{
SLE::pointer sleCancel = mEngine->entryCache (ltOFFER,
getOfferIndex (mTxnAccountID, uCancelSequence));
@@ -682,7 +681,7 @@ public:
// empty (fully crossed), or something in-between.
core::Amounts place_offer;
m_journal.debug << "Attempting cross: " <<
m_journal.debug << "Attempting cross: " <<
to_string (taker_amount.in.issue ()) << " -> " <<
to_string (taker_amount.out.issue ());
@@ -724,7 +723,9 @@ public:
// never be negative. If it is, something went very very wrong.
if (place_offer.in < zero || place_offer.out < zero)
{
m_journal.fatal << "Cross left offer negative!";
m_journal.fatal << "Cross left offer negative!" <<
" in: " << format_amount (place_offer.in) <<
" out: " << format_amount (place_offer.out);
return tefINTERNAL;
}
@@ -762,7 +763,7 @@ public:
{
m_journal.trace << "Fill or Kill: offer killed";
view.swapWith (view_checkpoint);
return result;
return tesSUCCESS;
}
// For 'immediate or cancel' offers, the amount remaining doesn't get
@@ -770,17 +771,20 @@ public:
if (bImmediateOrCancel)
{
m_journal.trace << "Immediate or cancel: offer cancelled";
return result;
return tesSUCCESS;
}
if (mPriorBalance.getNValue () < getAccountReserve (sleCreator))
{
// If we are here, the signing account had an insufficient reserve
// *prior* to our processing. If something actually crossed, then
// allow this; otherwise, we just claim a fee.
// we allow this; otherwise, we just claim a fee.
if (!crossed)
result = tecINSUF_RESERVE_OFFER;
if (bOpenLedger && ripple::legacy::emulate027 (mEngine->getLedger()))
result = tecINSUF_RESERVE_OFFER;
if (result != tesSUCCESS)
m_journal.debug << "final result: " << transToken (result);
@@ -862,7 +866,7 @@ transact_CreateOffer (
{
// Attempt to implement legacy offer creation semantics. If successful,
// then return the result. Otherwise, attempt to process using the
// new semantics.
// new semantics.
auto ret = ripple::legacy::transact_CreateOffer (txn, params, engine);
if (ret.first)

View File

@@ -36,9 +36,7 @@ class CreateOffer
{
private:
// What kind of offer we are placing
#if RIPPLE_ENABLE_AUTOBRIDGING
bool autobridging_;
#endif
// Determine if we are authorized to hold the asset we want to get
TER

View File

@@ -20,6 +20,7 @@
#include <BeastConfig.h>
#include <ripple/core/Config.h>
#include <ripple/app/transactors/Transactor.h>
#include <ripple/legacy/0.27/Emulate027.h>
#include <ripple/protocol/Indexes.h>
namespace ripple {
@@ -200,6 +201,11 @@ TER Transactor::checkSeq ()
return tefPAST_SEQ;
}
if (ripple::legacy::emulate027 (mEngine->getLedger()) &&
mTxn.isFieldPresent (sfPreviousTxnID) &&
(mTxnAccount->getFieldH256 (sfPreviousTxnID) != mTxn.getFieldH256 (sfPreviousTxnID)))
return tefWRONG_PRIOR;
if (mTxn.isFieldPresent (sfAccountTxnID) &&
(mTxnAccount->getFieldH256 (sfAccountTxnID) != mTxn.getFieldH256 (sfAccountTxnID)))
return tefWRONG_PRIOR;

View File

@@ -34,8 +34,8 @@ emulate027 (Ledger::ref ledger)
return false;
// The server also uses 0.28 semantics for all ledgers whose parent
// closed after 2015-03-30 13:00:00 PDT.
static std::uint32_t const legacy_cutoff = 481060800;
// closed after 2015-04-15 13:00:00 PDT.
static std::uint32_t const legacy_cutoff = 482442800;
if (ledger->getParentCloseTimeNC () > legacy_cutoff)
return false;

View File

@@ -29,8 +29,10 @@
#include <ripple/protocol/TxFlags.h>
#include <ripple/basics/StringUtilities.h>
#include <ripple/json/to_string.h>
#include <ripple/legacy/0.27/Emulate027.h>
#include <beast/unit_test/suite.h>
#include <boost/format.hpp>
#include "boost/date_time/posix_time/posix_time.hpp"
#include <array>
namespace ripple {
@@ -290,7 +292,14 @@ isMemoOkay (STObject const& st, std::string& reason)
if (!st.isFieldPresent (sfMemos))
return true;
const STArray& memos = st.getFieldArray (sfMemos);
// We switch to new semantics on April 15, 2015 at 1:00pm PDT:
static boost::posix_time::ptime const cutoff (
boost::posix_time::time_from_string ("2015-04-15 20:00:00"));
bool const emulate027 =
boost::posix_time::second_clock::universal_time () < cutoff;
auto const& memos = st.getFieldArray (sfMemos);
// The number 2048 is a preallocation hint, not a hard limit
// to avoid allocate/copy/free's
@@ -327,6 +336,9 @@ isMemoOkay (STObject const& st, std::string& reason)
return false;
}
if (emulate027)
continue;
// The raw data is stored as hex-octets, which we want to decode.
auto data = strUnHex (memoElement.getText ());

View File

@@ -96,6 +96,7 @@ void TxFormats::addCommonFields (Item& item)
<< SOElement(sfSourceTag, SOE_OPTIONAL)
<< SOElement(sfAccount, SOE_REQUIRED)
<< SOElement(sfSequence, SOE_REQUIRED)
<< SOElement(sfPreviousTxnID, SOE_OPTIONAL) // emulate027
<< SOElement(sfLastLedgerSequence, SOE_OPTIONAL)
<< SOElement(sfAccountTxnID, SOE_OPTIONAL)
<< SOElement(sfFee, SOE_REQUIRED)

View File

@@ -19,10 +19,10 @@
#include <BeastConfig.h>
#include <ripple/legacy/0.27/book/impl/BookTip.cpp>
#include <ripple/legacy/0.27/book/impl/OfferStream.cpp>
#include <ripple/legacy/0.27/book/impl/Quality.cpp>
#include <ripple/legacy/0.27/book/impl/Taker.cpp>
#include <ripple/legacy/0.27/CreateOffer.cpp>
#include <ripple/legacy/0.27/book/impl/BookTip27.cpp>
#include <ripple/legacy/0.27/book/impl/OfferStream27.cpp>
#include <ripple/legacy/0.27/book/impl/Quality27.cpp>
#include <ripple/legacy/0.27/book/impl/Taker27.cpp>
#include <ripple/legacy/0.27/CreateOffer27.cpp>
#include <ripple/legacy/0.27/Emulate027.cpp>