diff --git a/Builds/VisualStudio2013/RippleD.vcxproj b/Builds/VisualStudio2013/RippleD.vcxproj
index 154daf6e2..4f766ac45 100644
--- a/Builds/VisualStudio2013/RippleD.vcxproj
+++ b/Builds/VisualStudio2013/RippleD.vcxproj
@@ -2442,19 +2442,19 @@
-
+
True
True
-
+
True
True
-
+
True
True
-
+
True
True
@@ -2468,12 +2468,12 @@
-
+
+
+
True
True
-
-
True
True
@@ -4496,8 +4496,6 @@
-
-
diff --git a/Builds/VisualStudio2013/RippleD.vcxproj.filters b/Builds/VisualStudio2013/RippleD.vcxproj.filters
index c54cf2c14..a2815711d 100644
--- a/Builds/VisualStudio2013/RippleD.vcxproj.filters
+++ b/Builds/VisualStudio2013/RippleD.vcxproj.filters
@@ -3003,16 +3003,16 @@
ripple\legacy\0.27\book
-
+
ripple\legacy\0.27\book\impl
-
+
ripple\legacy\0.27\book\impl
-
+
ripple\legacy\0.27\book\impl
-
+
ripple\legacy\0.27\book\impl
@@ -3030,12 +3030,12 @@
ripple\legacy\0.27\book
-
- ripple\legacy\0.27
-
ripple\legacy\0.27
+
+ ripple\legacy\0.27
+
ripple\legacy\0.27
@@ -5268,9 +5268,6 @@
soci\src\core
-
- soci\src\core
-
sqlite
diff --git a/src/BeastConfig.h b/src/BeastConfig.h
index 74833e2a4..15ad99372 100644
--- a/src/BeastConfig.h
+++ b/src/BeastConfig.h
@@ -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.
diff --git a/src/ripple/app/ledger/LedgerEntrySet.cpp b/src/ripple/app/ledger/LedgerEntrySet.cpp
index 73bad24b1..030890d8e 100644
--- a/src/ripple/app/ledger/LedgerEntrySet.cpp
+++ b/src/ripple/app/ledger/LedgerEntrySet.cpp
@@ -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 (flags & (!bIssuerHigh ? lsfLowNoRipple : lsfHighNoRipple)) !=
- static_cast (entryCache (ltACCOUNT_ROOT,
- getAccountRootIndex (sender))->getFlags() & lsfDefaultRipple)
- && !(flags & (!bIssuerHigh ? lsfLowFreeze : lsfHighFreeze))
+ && static_cast (flags & (!bSenderHigh ? lsfLowNoRipple : lsfHighNoRipple)) !=
+ static_cast (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);
diff --git a/src/ripple/app/ledger/LedgerEntrySet.h b/src/ripple/app/ledger/LedgerEntrySet.h
index 91d569fd8..1f98b4c30 100644
--- a/src/ripple/app/ledger/LedgerEntrySet.h
+++ b/src/ripple/app/ledger/LedgerEntrySet.h
@@ -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);
};
diff --git a/src/ripple/app/transactors/CreateOffer.cpp b/src/ripple/app/transactors/CreateOffer.cpp
index 2201378ec..409a507ee 100644
--- a/src/ripple/app/transactors/CreateOffer.cpp
+++ b/src/ripple/app/transactors/CreateOffer.cpp
@@ -28,6 +28,7 @@
#include
#include
+#include
#include
#include
@@ -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
@@ -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)
diff --git a/src/ripple/app/transactors/CreateOffer.h b/src/ripple/app/transactors/CreateOffer.h
index 28299e5b8..c086bd373 100644
--- a/src/ripple/app/transactors/CreateOffer.h
+++ b/src/ripple/app/transactors/CreateOffer.h
@@ -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
diff --git a/src/ripple/app/transactors/Transactor.cpp b/src/ripple/app/transactors/Transactor.cpp
index 8015ffa92..563788214 100644
--- a/src/ripple/app/transactors/Transactor.cpp
+++ b/src/ripple/app/transactors/Transactor.cpp
@@ -20,6 +20,7 @@
#include
#include
#include
+#include
#include
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;
diff --git a/src/ripple/legacy/0.27/CreateOffer.cpp b/src/ripple/legacy/0.27/CreateOffer27.cpp
similarity index 100%
rename from src/ripple/legacy/0.27/CreateOffer.cpp
rename to src/ripple/legacy/0.27/CreateOffer27.cpp
diff --git a/src/ripple/legacy/0.27/Emulate027.cpp b/src/ripple/legacy/0.27/Emulate027.cpp
index 6c9524e00..8de077a21 100644
--- a/src/ripple/legacy/0.27/Emulate027.cpp
+++ b/src/ripple/legacy/0.27/Emulate027.cpp
@@ -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;
diff --git a/src/ripple/legacy/0.27/book/impl/BookTip.cpp b/src/ripple/legacy/0.27/book/impl/BookTip27.cpp
similarity index 100%
rename from src/ripple/legacy/0.27/book/impl/BookTip.cpp
rename to src/ripple/legacy/0.27/book/impl/BookTip27.cpp
diff --git a/src/ripple/legacy/0.27/book/impl/OfferStream.cpp b/src/ripple/legacy/0.27/book/impl/OfferStream27.cpp
similarity index 100%
rename from src/ripple/legacy/0.27/book/impl/OfferStream.cpp
rename to src/ripple/legacy/0.27/book/impl/OfferStream27.cpp
diff --git a/src/ripple/legacy/0.27/book/impl/Quality.cpp b/src/ripple/legacy/0.27/book/impl/Quality27.cpp
similarity index 100%
rename from src/ripple/legacy/0.27/book/impl/Quality.cpp
rename to src/ripple/legacy/0.27/book/impl/Quality27.cpp
diff --git a/src/ripple/legacy/0.27/book/impl/Taker.cpp b/src/ripple/legacy/0.27/book/impl/Taker27.cpp
similarity index 100%
rename from src/ripple/legacy/0.27/book/impl/Taker.cpp
rename to src/ripple/legacy/0.27/book/impl/Taker27.cpp
diff --git a/src/ripple/protocol/impl/STTx.cpp b/src/ripple/protocol/impl/STTx.cpp
index f2a5d875c..a6185918b 100644
--- a/src/ripple/protocol/impl/STTx.cpp
+++ b/src/ripple/protocol/impl/STTx.cpp
@@ -29,8 +29,10 @@
#include
#include
#include
+#include
#include
#include
+#include "boost/date_time/posix_time/posix_time.hpp"
#include
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 ());
diff --git a/src/ripple/protocol/impl/TxFormats.cpp b/src/ripple/protocol/impl/TxFormats.cpp
index 4aceb6494..ee0cb093c 100644
--- a/src/ripple/protocol/impl/TxFormats.cpp
+++ b/src/ripple/protocol/impl/TxFormats.cpp
@@ -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)
diff --git a/src/ripple/unity/legacy.cpp b/src/ripple/unity/legacy.cpp
index 7debd523c..4869ad569 100644
--- a/src/ripple/unity/legacy.cpp
+++ b/src/ripple/unity/legacy.cpp
@@ -19,10 +19,10 @@
#include
-#include
-#include
-#include
-#include
-#include
+#include
+#include
+#include
+#include
+#include
#include