Various cleanups:

* Replace SYSTEM_NAME and other macros with C++ constructs
* Remove RIPPLE_ARRAYSIZE and use std::extent or ranged for loops
* Remove old-style, unused offer crossing unit test
* Make STAmount::saFromRate free and remove default argument
This commit is contained in:
Nik Bougalis
2014-12-04 03:16:41 -08:00
parent 8e792855e0
commit 4a49fefdd9
27 changed files with 305 additions and 1152 deletions

View File

@@ -2116,8 +2116,6 @@
</ClCompile>
<ClInclude Include="..\..\src\ripple\app\websocket\WSServerHandler.h">
</ClInclude>
<ClInclude Include="..\..\src\ripple\basics\ArraySize.h">
</ClInclude>
<ClInclude Include="..\..\src\ripple\basics\BasicConfig.h">
</ClInclude>
<ClInclude Include="..\..\src\ripple\basics\BasicTypes.h">
@@ -2198,9 +2196,6 @@
</ClInclude>
<ClInclude Include="..\..\src\ripple\basics\TaggedCache.h">
</ClInclude>
<ClCompile Include="..\..\src\ripple\basics\tests\cross_offer.test.cpp">
<ExcludedFromBuild>True</ExcludedFromBuild>
</ClCompile>
<ClInclude Include="..\..\src\ripple\basics\ThreadName.h">
</ClInclude>
<ClInclude Include="..\..\src\ripple\basics\Time.h">

View File

@@ -337,9 +337,6 @@
<Filter Include="ripple\basics\impl">
<UniqueIdentifier>{1B5E3484-E132-ADEA-8A38-01B0F4ABAC58}</UniqueIdentifier>
</Filter>
<Filter Include="ripple\basics\tests">
<UniqueIdentifier>{B1F0C3D5-71C4-3ABF-E292-F147387D07CB}</UniqueIdentifier>
</Filter>
<Filter Include="ripple\core">
<UniqueIdentifier>{235DCF23-2CF8-4F03-1A54-C159823A7E8D}</UniqueIdentifier>
</Filter>
@@ -3048,9 +3045,6 @@
<ClInclude Include="..\..\src\ripple\app\websocket\WSServerHandler.h">
<Filter>ripple\app\websocket</Filter>
</ClInclude>
<ClInclude Include="..\..\src\ripple\basics\ArraySize.h">
<Filter>ripple\basics</Filter>
</ClInclude>
<ClInclude Include="..\..\src\ripple\basics\BasicConfig.h">
<Filter>ripple\basics</Filter>
</ClInclude>
@@ -3150,9 +3144,6 @@
<ClInclude Include="..\..\src\ripple\basics\TaggedCache.h">
<Filter>ripple\basics</Filter>
</ClInclude>
<ClCompile Include="..\..\src\ripple\basics\tests\cross_offer.test.cpp">
<Filter>ripple\basics\tests</Filter>
</ClCompile>
<ClInclude Include="..\..\src\ripple\basics\ThreadName.h">
<Filter>ripple\basics</Filter>
</ClInclude>

View File

@@ -92,7 +92,7 @@ Taker::flow (Amounts amount, Offer const& offer, Account const& taker)
}
else
{
Amount const taker_charge (Amount::saFromRate (taker_charge_rate));
Amount const taker_charge (amountFromRate (taker_charge_rate));
amount = offer.quality ().ceil_in (amount,
divide (taker_funds, taker_charge));
}
@@ -116,7 +116,7 @@ Taker::flow (Amounts amount, Offer const& offer, Account const& taker)
}
else
{
Amount const owner_charge (Amount::saFromRate (owner_charge_rate));
Amount const owner_charge (amountFromRate (owner_charge_rate));
owner_amount = offer.quality ().ceil_out (owner_amount,
divide (owner_funds, owner_charge));
}

View File

@@ -1276,12 +1276,8 @@ STAmount LedgerEntrySet::rippleTransferFee (
if (QUALITY_ONE != uTransitRate)
{
// NIKB use STAmount::saFromRate
STAmount saTransitRate (
noIssue(), static_cast<std::uint64_t> (uTransitRate), -9);
STAmount saTransferTotal = multiply (
saAmount, saTransitRate, saAmount.issue ());
saAmount, amountFromRate (uTransitRate), saAmount.issue ());
STAmount saTransferFee = saTransferTotal - saAmount;
WriteLog (lsDEBUG, LedgerEntrySet) << "rippleTransferFee:" <<

View File

@@ -84,7 +84,7 @@ void startServer ()
void printHelp (const po::options_description& desc)
{
std::cerr
<< SYSTEM_NAME "d [options] <command> <params>\n"
<< systemName () << "d [options] <command> <params>\n"
<< desc << std::endl
<< "Commands: \n"
" account_info <account>|<seed>|<pass_phrase>|<key> [<ledger>] [strict]\n"

View File

@@ -17,9 +17,9 @@
*/
//==============================================================================
#include <ripple/basics/ArraySize.h>
#include <boost/algorithm/string.hpp>
#include <boost/regex.hpp>
#include <type_traits>
namespace ripple {
@@ -154,8 +154,15 @@ bool ProofOfWork::checkSolution (uint256 const& solution) const
bool ProofOfWork::validateToken (std::string const& strToken)
{
static boost::regex reToken ("[[:xdigit:]]{64}-[[:xdigit:]]{64}-[[:digit:]]+-[[:digit:]]+-[[:xdigit:]]{64}");
boost::smatch smMatch;
static boost::regex const reToken (
"[[:xdigit:]]{64}-"
"[[:xdigit:]]{64}-"
"[[:digit:]]+-"
"[[:digit:]]+-"
"[[:xdigit:]]{64}",
boost::regex_constants::optimize);
boost::smatch smMatch;
return boost::regex_match (strToken, smMatch, reToken);
}
@@ -164,34 +171,35 @@ bool ProofOfWork::validateToken (std::string const& strToken)
bool ProofOfWork::calcResultInfo (PowResult powCode, std::string& strToken, std::string& strHuman)
{
static struct
struct PowResultInfo
{
PowResult powCode;
const char* cpToken;
const char* cpHuman;
} powResultInfoA[] =
{
{ powREUSED, "powREUSED", "Proof-of-work has already been used." },
{ powBADNONCE, "powBADNONCE", "The solution does not meet the required difficulty." },
{ powEXPIRED, "powEXPIRED", "Token is expired." },
{ powCORRUPT, "powCORRUPT", "Invalid token." },
{ powTOOEASY, "powTOOEASY", "Difficulty has increased since token was issued." },
{ powOK, "powOK", "Valid proof-of-work." },
PowResult code;
char const* token;
char const* text;
};
int iIndex = RIPPLE_ARRAYSIZE (powResultInfoA);
while (iIndex-- && powResultInfoA[iIndex].powCode != powCode)
;
if (iIndex >= 0)
static
PowResultInfo const results[] =
{
strToken = powResultInfoA[iIndex].cpToken;
strHuman = powResultInfoA[iIndex].cpHuman;
{ powOK, "powOK", "Valid proof-of-work." },
{ powREUSED, "powREUSED", "Proof-of-work has already been used." },
{ powBADNONCE, "powBADNONCE", "The solution does not meet the required difficulty." },
{ powEXPIRED, "powEXPIRED", "Token is expired." },
{ powCORRUPT, "powCORRUPT", "Invalid token." },
{ powTOOEASY, "powTOOEASY", "Difficulty has increased since token was issued." },
};
for (auto const& result : results)
{
if (powCode == result.code)
{
strToken = result.token;
strHuman = result.text;
return true;
}
}
return iIndex >= 0;
return false;
}
} // ripple

View File

@@ -17,8 +17,8 @@
*/
//==============================================================================
#include <ripple/basics/ArraySize.h>
#include <ripple/app/node/SqliteFactory.h>
#include <type_traits>
namespace ripple {
@@ -44,8 +44,6 @@ static const char* s_nodeStoreDBInit [] =
"END TRANSACTION;"
};
static int s_nodeStoreDBCount = RIPPLE_ARRAYSIZE (s_nodeStoreDBInit);
//------------------------------------------------------------------------------
class SqliteBackend : public NodeStore::Backend
@@ -53,8 +51,8 @@ class SqliteBackend : public NodeStore::Backend
public:
explicit SqliteBackend (std::string const& path, int hashnode_cache_size)
: m_name (path)
, m_db (new DatabaseCon(setup_DatabaseCon (getConfig()),
path, s_nodeStoreDBInit, s_nodeStoreDBCount))
, m_db (new DatabaseCon(setup_DatabaseCon (getConfig()), path,
s_nodeStoreDBInit, std::extent<decltype(s_nodeStoreDBInit)>::value))
{
std::string s ("PRAGMA cache_size=-");
s += std::to_string (hashnode_cache_size);

View File

@@ -230,7 +230,7 @@ TER RippleCalc::rippleCalculate ()
<< "rippleCalc: AFTER:"
<< " mIndex=" << pathState->index()
<< " uQuality=" << pathState->quality()
<< " rate=" << STAmount::saFromRate (pathState->quality());
<< " rate=" << amountFromRate (pathState->quality());
if (!pathState->quality())
{
@@ -257,7 +257,7 @@ TER RippleCalc::rippleCalculate ()
lsDEBUG, RippleCalc)
<< "rippleCalc: better:"
<< " uQuality="
<< STAmount::saFromRate (pathState->quality())
<< amountFromRate (pathState->quality())
<< " inPass()=" << pathState->inPass()
<< " saOutPass=" << pathState->outPass();
@@ -278,7 +278,7 @@ TER RippleCalc::rippleCalculate ()
<< " mIndex=" << pathState->index()
<< " uQuality=" << pathState->quality()
<< " rate="
<< STAmount::saFromRate (pathState->quality())
<< amountFromRate (pathState->quality())
<< " inPass()=" << pathState->inPass()
<< " saOutPass=" << pathState->outPass();
@@ -306,7 +306,7 @@ TER RippleCalc::rippleCalculate ()
<< "rippleCalc: "
<< "Summary: " << pathState->index()
<< " rate: "
<< STAmount::saFromRate (pathState->quality())
<< amountFromRate (pathState->quality())
<< " quality:" << pathState->quality()
<< " best: " << (iBest == pathState->index ());
}
@@ -320,7 +320,7 @@ TER RippleCalc::rippleCalculate ()
WriteLog (lsDEBUG, RippleCalc)
<< "rippleCalc: best:"
<< " uQuality="
<< STAmount::saFromRate (pathState->quality())
<< amountFromRate (pathState->quality())
<< " inPass()=" << pathState->inPass()
<< " saOutPass=" << pathState->outPass();

View File

@@ -52,7 +52,7 @@ TER PathCursor::reverseLiquidity () const
// a fee when third parties transfer that account's own issuances.
// node.transferRate_ caches the output transfer rate for this node.
node().transferRate_ = STAmount::saFromRate (
node().transferRate_ = amountFromRate (
rippleTransferRate (ledger(), node().issue_.account));
if (node().isAccount ())

View File

@@ -205,7 +205,7 @@ TER PathCursor::reverseLiquidityForAccount () const
<< " (available) previousNode.saRevRedeem="
<< previousNode().saRevRedeem
<< " uRateMax="
<< STAmount::saFromRate (uRateMax).getText ();
<< amountFromRate (uRateMax).getText ();
}
else
{

View File

@@ -39,8 +39,6 @@ namespace ripple {
#define NODE_FETCH_JOBS 10
#define NODE_FETCH_SECONDS 10
#define NODE_FILE_BYTES_MAX (50<<10) // 50k
#define NODE_FILE_NAME SYSTEM_NAME ".txt"
#define NODE_FILE_PATH "/" NODE_FILE_NAME
// Wait for validation information to be stable before scoring.
// #define SCORE_DELAY_SECONDS 20
@@ -118,6 +116,8 @@ public:
, mFetchActive (0)
, m_fetchTimer (this)
{
node_file_name_ = std::string (systemName ()) + ".txt";
node_file_path_ = "/" + node_file_name_;
}
//--------------------------------------------------------------------------
@@ -1161,19 +1161,19 @@ private:
if (!bReject)
{
IniFileSections secSite = parseIniFile (strSiteFile, true);
bool bGood = !err;
IniFileSections secSite = parseIniFile (strSiteFile, true);
bool bGood = !err;
if (bGood)
{
WriteLog (lsTRACE, UniqueNodeList) << boost::format ("Validator: '%s' received " NODE_FILE_NAME ".") % strDomain;
WriteLog (lsTRACE, UniqueNodeList) << strDomain
<< ": retrieved configuration";
}
else
{
WriteLog (lsTRACE, UniqueNodeList)
<< boost::format ("Validator: '%s' unable to retrieve " NODE_FILE_NAME ": %s")
% strDomain
% err.message ();
WriteLog (lsTRACE, UniqueNodeList) << strDomain
<< ": unable to retrieve configuration: "
<< err.message ();
}
//
@@ -1185,19 +1185,17 @@ private:
{
bGood = false;
WriteLog (lsTRACE, UniqueNodeList)
<< boost::format ("Validator: '%s' bad " NODE_FILE_NAME " missing single entry for " SECTION_DOMAIN ".")
% strDomain;
WriteLog (lsTRACE, UniqueNodeList) << strDomain
<< ": " << SECTION_DOMAIN
<< "entry missing.";
}
if (bGood && strSite != strDomain)
{
bGood = false;
WriteLog (lsTRACE, UniqueNodeList)
<< boost::format ("Validator: '%s' bad " NODE_FILE_NAME " " SECTION_DOMAIN " does not match: %s")
% strDomain
% strSite;
WriteLog (lsTRACE, UniqueNodeList) << strDomain
<< ": " << SECTION_DOMAIN << " does not match " << strSite;
}
//
@@ -1210,9 +1208,8 @@ private:
// Bad [validation_public_key] IniFileSections.
bGood = false;
WriteLog (lsTRACE, UniqueNodeList)
<< boost::format ("Validator: '%s' bad " NODE_FILE_NAME " " SECTION_PUBLIC_KEY " does not have single entry.")
% strDomain;
WriteLog (lsTRACE, UniqueNodeList) << strDomain
<< ": " << SECTION_PUBLIC_KEY << " entry missing.";
}
RippleAddress naNodePublic;
@@ -1222,16 +1219,13 @@ private:
// Bad public key.
bGood = false;
WriteLog (lsTRACE, UniqueNodeList)
<< boost::format ("Validator: '%s' bad " NODE_FILE_NAME " " SECTION_PUBLIC_KEY " is bad: ")
% strDomain
% strNodePublicKey;
WriteLog (lsTRACE, UniqueNodeList) << strDomain
<< ": " << SECTION_PUBLIC_KEY << " is not a public key: "
<< strNodePublicKey;
}
if (bGood)
{
// WriteLog (lsTRACE, UniqueNodeList) << boost::format("naNodePublic: '%s'") % naNodePublic.humanNodePublic();
seedDomain sdCurrent;
bool bFound = getSeedDomains (strDomain, sdCurrent);
@@ -1255,12 +1249,14 @@ private:
if (bChangedB)
{
WriteLog (lsTRACE, UniqueNodeList) << boost::format ("Validator: '%s' processing new " NODE_FILE_NAME ".") % strDomain;
WriteLog (lsTRACE, UniqueNodeList) << strDomain
<< ": processing new " << node_file_name_ << ".";
processFile (strDomain, naNodePublic, secSite);
}
else
{
WriteLog (lsTRACE, UniqueNodeList) << boost::format ("Validator: '%s' no change for " NODE_FILE_NAME ".") % strDomain;
WriteLog (lsTRACE, UniqueNodeList) << strDomain
<< ": no change in " << node_file_name_ << ".";
fetchFinish ();
}
}
@@ -1361,7 +1357,8 @@ private:
setSeedDomains (sdCurrent, false);
WriteLog (lsTRACE, UniqueNodeList) << "Validator: '" << strDomain << "' fetching " NODE_FILE_NAME ".";
WriteLog (lsTRACE, UniqueNodeList) << strDomain
<< " fetching " << node_file_name_ << ".";
fetchProcess (strDomain); // Go get it.
@@ -1401,14 +1398,15 @@ private:
// Get the ripple.txt and process it.
void fetchProcess (std::string strDomain)
{
WriteLog (lsTRACE, UniqueNodeList) << "Fetching '" NODE_FILE_NAME "' from '" << strDomain << "'.";
WriteLog (lsTRACE, UniqueNodeList) << strDomain
<< ": fetching " << node_file_name_ << ".";
std::deque<std::string> deqSites;
// Order searching from most specifically for purpose to generic.
// This order allows the client to take the most burden rather than the servers.
deqSites.push_back (str (boost::format (SYSTEM_NAME ".%s") % strDomain));
deqSites.push_back (str (boost::format ("www.%s") % strDomain));
deqSites.push_back (systemName () + strDomain);
deqSites.push_back ("www." + strDomain);
deqSites.push_back (strDomain);
HTTPClient::get (
@@ -1416,7 +1414,7 @@ private:
getApp().getIOService (),
deqSites,
443,
NODE_FILE_PATH,
node_file_path_,
NODE_FILE_BYTES_MAX,
boost::posix_time::seconds (NODE_FETCH_SECONDS),
std::bind (&UniqueNodeListImp::responseFetch, this, strDomain,
@@ -1734,7 +1732,8 @@ private:
//
// Process Validators
//
processValidators (strDomain, NODE_FILE_NAME, naNodePublic, vsReferral, getIniFileSection (secSite, SECTION_VALIDATORS));
processValidators (strDomain, node_file_name_, naNodePublic,
vsReferral, getIniFileSection (secSite, SECTION_VALIDATORS));
//
// Process ips
@@ -2047,6 +2046,9 @@ private:
beast::DeadlineTimer m_fetchTimer; // Timer to start fetching.
std::map<RippleAddress, ClusterNodeStatus> m_clusterNodes;
std::string node_file_name_;
std::string node_file_path_;
};
//------------------------------------------------------------------------------

View File

@@ -461,10 +461,9 @@ public:
}
cpClient->set_body (
"<!DOCTYPE html><html><head><title>" SYSTEM_NAME " Test</title>"
"</head><body><h1>" SYSTEM_NAME " Test</h1>"
"<p>This page shows that http(s) connectivity is working."
"</p></body></html>");
"<!DOCTYPE html><html><head><title>" + systemName () +
" Test</title></head>" + "<body><h1>" + systemName () +
" Test</h1><p>This page shows http(s) connectivity is working.</p></body></html>");
return true;
}
};

View File

@@ -1,30 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2012, 2013 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef RIPPLE_BASICS_ARRAYSIZE_H_INCLUDED
#define RIPPLE_BASICS_ARRAYSIZE_H_INCLUDED
namespace ripple {
// DEPRECATED
#define RIPPLE_ARRAYSIZE(x) (sizeof(x) / sizeof((x)[0]))
} // ripple
#endif

View File

@@ -1,820 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2012, 2013 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#include <beast/unit_test/suite.h>
#include <beast/utility/noexcept.h>
#include <algorithm>
#include <cassert>
#include <iostream>
#include <iterator>
#include <beast/cxx14/type_traits.h> // <type_traits>
#include <utility>
#include <vector>
namespace ripple {
namespace core {
/** Represents both a quality and amounts of currencies for trade.
Quality is the ratio of output currency to input currency, where
higher means better for the offer taker. The first element of
the pair is the amount of currency available for input into
the offer. The second element of the pair is the amount of currency
that comes out if the full amount of the input currency is provided.
This pair also represents a fraction, for example for specifying a
minimum quality.
Offer requirements:
`X` is the type `Offer`
`a`, `b` are values of type `X`
`X::amount_type`
The return type of `in` and `out`
`X a;`
Constructs an uninitialized offer
`a.in();`
`a.out();
*/
/** Returns `true` if the offer is consumed. */
template <class Offer>
bool
is_offer_consumed (Offer const& offer) noexcept
{
assert ((offer.in() != 0 && offer.out() != 0) ||
(offer.in() == 0 && offer.out() == 0));
return offer.in() == 0 || offer.out() == 0;
}
//------------------------------------------------------------------------------
template <class Amount>
struct AmountTraits
{
/** Returns `true` if `lhs` is of lower quality than `rhs`. */
template <class Offer>
static
bool
less (Offer const& lhs, Offer const& rhs) noexcept
{
assert (! is_offer_consumed (lhs));
assert (! is_offer_consumed (rhs));
assert (lhs.out() != 0);
assert (rhs.out() != 0);
return (lhs.out() / lhs.in()) < (rhs.out() / rhs.in());
}
/** Calculates the result of multiplying amount by the implied ratio. */
template <class Offer>
static
typename Offer::amount_type
multiply (typename Offer::amount_type const& amount, Offer const& rate)
{
// Avoid math when result is exact
if (amount == rate.in())
return rate.out();
typename Offer::amount_type const result (
amount * (rate.out() / rate.in()));
if (result > rate.out())
return rate.out();
return result;
}
template <class Offer>
static
Offer
inverse (Offer const& value) noexcept
{
return Offer (value.out(), value.in());
}
};
/** Returns the offer that would result if the input amount is applied. */
template <class Offer>
Offer
consume_offer (
typename Offer::amount_type const& input,
Offer offer)
{
using Amount = typename Offer::amount_type;
// We need to calculate the most that we can take:
Amount const input_used (std::min (input, offer.in()));
Amount const output (AmountTraits<Amount>::multiply (input_used, offer));
offer.in() -= input_used;
offer.out() -= output;
return offer;
}
/** Fills an order amount in an order book.
@return The resulting amount of currency in and out.
*/
template <class BookIter>
typename std::iterator_traits<BookIter>::value_type
cross_offer_in (
typename std::iterator_traits<BookIter>::value_type::amount_type const& in,
typename std::iterator_traits<BookIter>::value_type const& minimum_quality,
BookIter first, BookIter last)
{
using Amount =
typename std::iterator_traits<BookIter>::value_type::amount_type;
using Offer =
typename std::iterator_traits<BookIter>::value_type;
Offer result {0, 0};
Amount remain (in);
for (auto iter (first); (result.in() < in) && (iter != last); ++iter)
{
Offer const offer (*iter);
if (AmountTraits<Amount>::less (offer, minimum_quality))
break;
Offer const offer_out (consume_offer (remain, offer));
result.in() += offer.in() - offer_out.in();
result.out() += offer.out() - offer_out.out();
*iter = offer_out;
}
return result;
}
//------------------------------------------------------------------------------
/** Returns the composite A->C from offers A->B and B->C, equal liquidity. */
template <class Offer>
Offer
make_bridged_offer (Offer const& leg1, Offer const& leg2)
{
using Amount = typename Offer::amount_type;
// Skip math if both legs can be fully consumed
if (leg1.out() == leg2.in())
return Offer (leg1.in(), leg2.out());
// If leg2 has less liquidity, scale down by leg2
if (leg1.out() > leg2.in())
return Offer (
AmountTraits<Amount>::multiply (leg2.in(),
AmountTraits<Amount>::inverse (leg1)),
leg2.out());
// leg1 has less liquidity
return Offer (leg1.in(),
AmountTraits<Amount>::multiply (leg1.out(), leg2));
}
namespace detail {
/** Presents a set of order books as a single bridged order book. */
template <class BookIter>
class MultiBookIterator
{
private:
using Amount =
typename std::iterator_traits<BookIter>::value_type::amount_type;
using Offer =
typename std::iterator_traits<BookIter>::value_type;
typedef std::is_const <
typename std::iterator_traits<BookIter>::reference
> IsConst;
struct forward_iterator_base_tag
: std::output_iterator_tag
, std::forward_iterator_tag
{
forward_iterator_base_tag()
{
}
};
struct forward_const_iterator_base_tag
: std::forward_iterator_tag
{
forward_const_iterator_base_tag()
{
}
};
template <class>
friend class MultiBookIterator;
BookIter m_direct;
BookIter m_direct_end;
BookIter m_leg1;
BookIter m_leg1_end;
BookIter m_leg2;
BookIter m_leg2_end;
bool m_bridged;
Offer m_offer;
class Proxy : public Offer
{
private:
bool m_bridged;
BookIter m_direct;
BookIter m_leg1;
BookIter m_leg2;
public:
explicit Proxy (BookIter direct)
: Offer (*direct)
, m_bridged (false)
, m_direct (direct)
{
}
Proxy (BookIter leg1, BookIter leg2)
: Offer (make_bridged_offer (*leg1, *leg2))
, m_bridged (true)
, m_leg1 (leg1)
, m_leg2 (leg2)
{
}
Proxy&
operator= (Offer const& offer)
{
if (m_bridged)
{
Offer const result (consume_offer (
offer.in(), *m_leg1));
*m_leg2 = consume_offer (
m_leg1->in() - result.in(), *m_leg2);
*m_leg1 = result;
}
else
{
*m_direct = offer;
}
((Offer&)*this) = offer;
return *this;
}
};
// Returns true if this iterator has reached the one past the end marker
bool
past_end() const noexcept
{
return
(m_direct == m_direct_end) &&
(m_leg1 == m_leg1_end || m_leg2 == m_leg2_end);
}
void
throw_if_past()
{
if (past_end())
throw std::out_of_range ("invalid iterator dereferenced");
}
// Returns true if the iterators are both equal, or both past the end
template <class Iter1, class Iter2>
static
bool
iter_eq (Iter1 iter1, Iter1 iter1_end,
Iter2 iter2, Iter2 iter2_end) noexcept
{
if (iter1 == iter1_end)
return iter2 == iter2_end;
if (iter2 == iter2_end)
return false;
return iter1 == iter2;
}
// Stores the best offer (if any) in m_offer
void
calc_offer()
{
if (past_end())
return;
// FIXME rewrite this - having 3 nested if's is overkill...
if ((m_leg1 != m_leg1_end) && (m_leg2 != m_leg2_end))
{
Offer const bridged (
make_bridged_offer (*m_leg1, *m_leg2));
if (m_direct != m_direct_end)
{
if (AmountTraits<Amount>::less (*m_direct, bridged))
{
m_bridged = true;
m_offer = bridged;
}
else
{
m_bridged = false;
m_offer = *m_direct;
}
}
else
{
m_bridged = true;
m_offer = bridged;
}
}
else
{
m_bridged = false;
m_offer = *m_direct;
}
}
public:
typedef std::ptrdiff_t difference_type;
typedef typename std::iterator_traits <
BookIter>::value_type value_type;
typedef value_type* pointer;
typedef value_type& reference;
typedef std::conditional_t <
std::is_const <std::remove_reference_t <reference>>::value,
forward_const_iterator_base_tag,
forward_iterator_base_tag> iterator_category;
MultiBookIterator () = default;
template <
class OtherBookIter,
class = std::enable_if_t <
std::is_same <value_type, typename OtherBookIter::value_type>::value
>
>
MultiBookIterator (MultiBookIterator <OtherBookIter> const& other)
: m_direct (other.m_direct)
, m_direct_end (other.m_direct_end)
, m_leg1 (other.m_leg1)
, m_leg1_end (other.m_leg1_end)
, m_leg2 (other.m_leg2)
, m_leg2_end (other.m_leg2_end)
{
}
template <
class OtherBookIter,
class = std::enable_if_t <
std::is_same <value_type, typename OtherBookIter::value_type>::value
>
>
MultiBookIterator (
OtherBookIter direct_first, OtherBookIter direct_last,
OtherBookIter leg1_first, OtherBookIter leg1_last,
OtherBookIter leg2_first, OtherBookIter leg2_last)
: m_direct (direct_first)
, m_direct_end (direct_last)
, m_leg1 (leg1_first)
, m_leg1_end (leg1_last)
, m_leg2 (leg2_first)
, m_leg2_end (leg2_last)
{
calc_offer();
}
MultiBookIterator&
operator++()
{
throw_if_past ();
if (m_direct != m_direct_end)
++m_direct;
if (m_leg1 != m_leg1_end)
++m_leg1;
if (m_leg2 != m_leg2_end)
++m_leg2;
calc_offer();
return *this;
}
MultiBookIterator
operator++(int)
{
MultiBookIterator prev (*this);
this->operator++();
return prev;
}
template <class OtherBookIter>
bool
operator== (
MultiBookIterator <OtherBookIter> const& other) const noexcept
{
if (! iter_eq (m_direct, m_direct_end,
other.m_direct, other.m_direct_end))
return false;
if (! iter_eq (m_leg1, m_leg1_end,
other.m_leg1, other.m_leg1_end))
return false;
if (! iter_eq (m_leg2, m_leg2_end,
other.m_leg2, other.m_leg2_end))
return false;
return true;
}
Offer const*
operator->() const
{
throw_if_past();
return &m_offer;
}
Offer const&
operator*() const
{
throw_if_past();
return m_offer;
}
#ifndef _MSC_VER
// This blows up Visual Studio
template <
bool MaybeConst = IsConst::value,
class = std::enable_if_t <! MaybeConst>
>
#endif
Proxy
operator*()
{
static_assert (! IsConst::value,
"invalid call of non-const member function");
throw_if_past();
if (m_bridged)
return Proxy (m_leg1, m_leg2);
return Proxy (m_direct);
}
};
template <class LeftBookIter, class RightBookIter>
bool
operator!= (
MultiBookIterator <LeftBookIter> const& lhs,
MultiBookIterator <RightBookIter> const& rhs) noexcept
{
return !(rhs == lhs);
}
} // detail
//------------------------------------------------------------------------------
// TODO Allow const Book
//
template <class Book>
class MultiBook
{
private:
static_assert (! std::is_const <Book>::value,
"Book cannot be const");
std::reference_wrapper<Book> m_direct;
std::reference_wrapper<Book> m_leg1;
std::reference_wrapper<Book> m_leg2;
public:
typedef typename Book::value_type value_type;
typedef typename Book::reference reference;
typedef typename Book::const_reference const_reference;
typedef detail::MultiBookIterator <
typename Book::iterator> iterator;
typedef detail::MultiBookIterator <
typename Book::const_iterator> const_iterator;
typedef typename Book::difference_type difference_type;
typedef typename Book::size_type size_type;
MultiBook (Book& direct, Book& leg1, Book& leg2)
: m_direct (direct)
, m_leg1 (leg1)
, m_leg2 (leg2)
{
}
bool
empty() const noexcept
{
return cbegin() == cend();
}
// Complexity: linear
size_type
size() const noexcept
{
return std::distance (cbegin(), cend());
}
iterator
begin() noexcept
{
return iterator (
m_direct.get().begin(), m_direct.get().end(),
m_leg1.get().begin(), m_leg1.get().end(),
m_leg2.get().begin(), m_leg2.get().end());
}
iterator
end() noexcept
{
return iterator (
m_direct.get().end(), m_direct.get().end(),
m_leg1.get().end(), m_leg1.get().end(),
m_leg2.get().end(), m_leg2.get().end());
}
const_iterator
begin() const noexcept
{
return const_iterator (
m_direct.get().cbegin(), m_direct.get().cend(),
m_leg1.get().cbegin(), m_leg1.get().cend(),
m_leg2.get().cbegin(), m_leg2.get().cend());
}
const_iterator
end() const noexcept
{
return const_iterator (
m_direct.get().cend(), m_direct.get().cend(),
m_leg1.get().cend(), m_leg1.get().cend(),
m_leg2.get().cend(), m_leg2.get().cend());
}
const_iterator
cbegin() const noexcept
{
return const_iterator (
m_direct.get().cbegin(), m_direct.get().cend(),
m_leg1.get().cbegin(), m_leg1.get().cend(),
m_leg2.get().cbegin(), m_leg2.get().cend());
}
const_iterator
cend() const noexcept
{
return const_iterator (
m_direct.get().cend(), m_direct.get().cend(),
m_leg1.get().cend(), m_leg1.get().cend(),
m_leg2.get().cend(), m_leg2.get().cend());
}
};
//------------------------------------------------------------------------------
template <class Book>
typename std::iterator_traits<typename Book::iterator>::value_type
cross_offer_in (
typename std::iterator_traits<
typename Book::iterator>::value_type::amount_type const& in,
typename std::iterator_traits <
typename Book::iterator>::value_type const& minimum_quality,
Book& book)
{
return cross_offer_in (in, minimum_quality, book.begin(), book.end());
}
template <class Book>
typename std::iterator_traits<typename Book::iterator>::value_type
cross_offer_in (
typename std::iterator_traits<
typename Book::iterator>::value_type::amount_type const& in,
typename std::iterator_traits<typename Book::iterator>::value_type
const& minimum_quality,
Book& direct, Book& leg1, Book& leg2)
{
MultiBook <Book> book (direct, leg1, leg2);
return cross_offer_in (in, minimum_quality, book);
}
//------------------------------------------------------------------------------
class cross_offers_test : public beast::unit_test::suite
{
public:
template <class Amount>
class OfferType
{
private:
Amount m_in;
Amount m_out;
public:
typedef Amount amount_type;
OfferType() = default;
OfferType (Amount const& in, Amount const& out) noexcept
: m_in (in)
, m_out (out)
{
assert ((m_in != 0 && m_out != 0) || (m_in == 0 && m_out == 0));
}
Amount const&
in() const noexcept
{
return m_in;
}
Amount&
in() noexcept
{
return m_in;
}
Amount const&
out() const noexcept
{
return m_out;
}
Amount&
out() noexcept
{
return m_out;
}
};
typedef double Amount;
typedef OfferType<Amount> Offer;
typedef std::vector <Offer> Book;
template <class Amount>
OfferType<Amount>
static make_offer (Amount from, Amount rate)
{
return OfferType<Amount> (from, from * rate);
}
template <class Book>
void
check_iterators (Book& b)
{
using Offer = typename Book::value_type;
// These make sure that expressions are well-formed
std::for_each (b.begin(), b.end(), [](Offer){});
std::for_each (b.cbegin(), b.cend(), [](Offer){});
{
Book const& cb (b);
std::for_each (cb.begin(), cb.end(), [](Offer){});
// Should not compile
//*cb.begin() = Book::value_type();
expect (cb.begin() == cb.end());
expect (cb.begin() == cb.cend());
}
expect (b.cbegin() == b.cend());
expect (b.begin() == b.cend());
typename Book::iterator iter;
typename Book::const_iterator citer (iter);
citer = typename Book::iterator();
}
void
test_iterators()
{
{
Book b;
check_iterators (b);
}
{
Book b1, b2, b3;
MultiBook <Book> b (b1, b2, b3);
check_iterators (b);
}
}
void
test_full_cross_auto_direct ()
{
testcase ("Autobridge (Full Direct Crossing)");
Book a_to_b;
a_to_b.push_back(make_offer(300., 2.0));
Book a_to_x;
a_to_x.push_back(make_offer(300., 0.5));
Book x_to_b;
x_to_b.push_back(make_offer(150., 0.5));
auto const rate = make_offer(50.0, 1.5);
Offer result = cross_offer_in (
50.0,
rate,
a_to_b, a_to_x, x_to_b);
expect ((result.in() == 50.0) && (result.out() == 100.0),
"Expected { 50.0 : 100.0 }");
}
void
test_full_cross_auto_bridge ()
{
testcase ("Autobridge (Full Bridge Crossing)");
Book a_to_b;
a_to_b.push_back(make_offer(300.00, 1.0));
Book a_to_x;
a_to_x.push_back(make_offer(300.00, 2.0));
Book x_to_b;
x_to_b.push_back(make_offer(300.00, 1.0));
auto const rate = make_offer(50.0, 1.5);
Offer result = cross_offer_in (
50.0,
rate,
a_to_b, a_to_x, x_to_b);
expect ((result.in() == 50.0) && (result.out() == 100.0),
"Expected { 50.0 : 100.0 }");
}
void
test_full_cross_direct ()
{
testcase ("Direct (Full Crossing)");
Book a_to_b;
a_to_b.push_back(make_offer(300.00, 2.0));
auto const rate = make_offer(50.0, 1.5);
Offer result = cross_offer_in (
50.0,
rate,
a_to_b);
expect ((result.in() == 50.0) && (result.out() == 100.0),
"Expected { 50.0 : 100.0 }");
}
void
test_partial_cross_direct ()
{
testcase ("Direct (Partial Crossing)");
Book a_to_b;
a_to_b.push_back(make_offer(25.00, 2.0));
auto const rate = make_offer(50.0, 1.5);
Offer result = cross_offer_in (
50.0,
rate,
a_to_b);
expect ((result.in() == 25.0) && (result.out() == 50.0),
"Expected { 25.0 : 50.0 }");
}
void
run()
{
test_iterators();
test_full_cross_direct ();
test_full_cross_auto_direct ();
test_full_cross_auto_bridge ();
test_partial_cross_direct ();
}
};
BEAST_DEFINE_TESTSUITE_MANUAL(cross_offers,orderbook_logic,ripple);
}
}

View File

@@ -20,50 +20,47 @@
#ifndef RIPPLE_CORE_SYSTEMPARAMETERS_H_INCLUDED
#define RIPPLE_CORE_SYSTEMPARAMETERS_H_INCLUDED
#include <cstdint>
namespace ripple {
/** Protocol specific constant globals. */
// VFALCO NOTE use these from now on instead of the macros!
class RippleSystem
/** Various protocol and system specific constant globals. */
/* The name of the system. */
static inline
std::string const&
systemName ()
{
public:
static inline char const* getSystemName ()
{
return "ripple";
}
static std::string const name = "ripple";
return name;
}
static char const* getCurrencyCode ()
{
return "XRP";
}
/** Configure the native currency. */
static
std::uint64_t const
SYSTEM_CURRENCY_GIFT = 1000;
static char const* getCurrencyCodeRipple ()
{
return "XRR";
}
static
std::uint64_t const
SYSTEM_CURRENCY_USERS = 100000000;
static int getCurrencyPrecision ()
{
return 6;
}
};
static
std::uint64_t const
SYSTEM_CURRENCY_PARTS = 1000000;
// VFALCO TODO I would love to replace these macros with the language
// constructs above. The problem is the way they are used at
// the point of call, i.e. "User-agent:" SYSTEM_NAME
// It will be necessary to rewrite some of them to use string streams.
//
#define SYSTEM_NAME "ripple"
#define SYSTEM_CURRENCY_PRECISION 6
/** Calculate the amount of native currency created at genesis. */
static
std::uint64_t const
SYSTEM_CURRENCY_START = SYSTEM_CURRENCY_GIFT * SYSTEM_CURRENCY_USERS * SYSTEM_CURRENCY_PARTS;
// VFALCO TODO Replace with C++11 long long constants
// VFALCO NOTE Apparently these are used elsewhere. Make them constants in the config
// or in the Application
//
#define SYSTEM_CURRENCY_GIFT 1000ull
#define SYSTEM_CURRENCY_USERS 100000000ull
#define SYSTEM_CURRENCY_PARTS 1000000ull // 10^SYSTEM_CURRENCY_PRECISION
#define SYSTEM_CURRENCY_START (SYSTEM_CURRENCY_GIFT*SYSTEM_CURRENCY_USERS*SYSTEM_CURRENCY_PARTS)
/* The currency code for the native currency. */
static inline
std::string const&
systemCurrencyCode ()
{
static std::string const code = "XRP";
return code;
}
} // ripple

View File

@@ -342,9 +342,9 @@ void Config::setup (std::string const& strConf, bool bQuiet)
strXdgDataHome = strHome + "/.local/share";
}
CONFIG_DIR = strXdgConfigHome + "/" SYSTEM_NAME;
CONFIG_DIR = strXdgConfigHome + "/" + systemName ();
CONFIG_FILE = CONFIG_DIR / strConfFile;
DATA_DIR = strXdgDataHome + "/" SYSTEM_NAME;
DATA_DIR = strXdgDataHome + "/" + systemName ();
boost::filesystem::create_directories (CONFIG_DIR, ec);

View File

@@ -18,13 +18,13 @@
//==============================================================================
#include <ripple/protocol/JsonFields.h>
#include <ripple/basics/ArraySize.h>
#include <ripple/rpc/ErrorCodes.h>
#include <ripple/server/ServerHandler.h>
#include <ripple/net/RPCCall.h>
#include <ripple/net/RPCErr.h>
#include <boost/regex.hpp>
#include <iostream>
#include <type_traits>
namespace ripple {
@@ -61,7 +61,7 @@ std::string createHTTPPost (
s << "POST "
<< (strPath.empty () ? "/" : strPath)
<< " HTTP/1.0\r\n"
<< "User-Agent: " SYSTEM_NAME "-json-rpc/v1\r\n"
<< "User-Agent: " << systemName () << "-json-rpc/v1\r\n"
<< "Host: " << strHost << "\r\n"
<< "Content-Type: application/json\r\n"
<< "Content-Length: " << strMsg.size () << "\r\n"
@@ -838,17 +838,25 @@ public:
// <-- { method: xyz, params: [... ] } or { error: ..., ... }
Json::Value parseCommand (std::string strMethod, Json::Value jvParams, bool allowAnyCommand)
{
WriteLog (lsTRACE, RPCParser) << "RPC method:" << strMethod;
WriteLog (lsTRACE, RPCParser) << "RPC params:" << jvParams;
if (ShouldLog (lsTRACE, RPCParser))
{
WriteLog (lsTRACE, RPCParser) << "RPC method:" << strMethod;
WriteLog (lsTRACE, RPCParser) << "RPC params:" << jvParams;
}
struct Command
{
const char* pCommand;
parseFuncPtr pfpFunc;
int iMinParams;
int iMaxParams;
const char* name;
parseFuncPtr parse;
int minParams;
int maxParams;
};
static Command commandsA[] =
// FIXME: replace this with a function-static std::map and the lookup
// code with std::map::find when the problem with magic statics on
// Visual Studio is fixed.
static
Command const commands[] =
{
// Request-response methods
// - Returns an error, or the request.
@@ -915,29 +923,33 @@ public:
{ "unsubscribe", &RPCParser::parseEvented, -1, -1 },
};
int i = RIPPLE_ARRAYSIZE (commandsA);
auto const count = jvParams.size ();
while (i-- && strMethod != commandsA[i].pCommand)
;
if (i < 0)
for (auto const& command : commands)
{
if (!allowAnyCommand)
return rpcError (rpcUNKNOWN_COMMAND);
if (strMethod == command.name)
{
if ((command.minParams >= 0 && count < command.minParams) ||
(command.maxParams >= 0 && count > command.maxParams))
{
WriteLog (lsDEBUG, RPCParser) <<
"Wrong number of parameters for " << command.name <<
" minimum=" << command.minParams <<
" maximum=" << command.maxParams <<
" actual=" << count;
return parseAsIs (jvParams);
}
else if ((commandsA[i].iMinParams >= 0 && jvParams.size () < commandsA[i].iMinParams)
|| (commandsA[i].iMaxParams >= 0 && jvParams.size () > commandsA[i].iMaxParams))
{
WriteLog (lsWARNING, RPCParser) << "Wrong number of parameters: minimum=" << commandsA[i].iMinParams
<< " maximum=" << commandsA[i].iMaxParams
<< " actual=" << jvParams.size ();
return rpcError (rpcBAD_SYNTAX);
}
return rpcError (rpcBAD_SYNTAX);
return (this->* (command.parse)) (jvParams);
}
}
return (this->* (commandsA[i].pfpFunc)) (jvParams);
// The command could not be found
if (!allowAnyCommand)
return rpcError (rpcUNKNOWN_COMMAND);
return parseAsIs (jvParams);
}
};

View File

@@ -122,13 +122,6 @@ public:
return construct (sit, name);
}
static
STAmount
saFromRate (std::uint64_t uRate = 0)
{
return STAmount (noIssue(), uRate, -9, false);
}
static
STAmount
deserialize (SerializerIterator&);
@@ -315,6 +308,9 @@ amountFromQuality (std::uint64_t rate);
STAmount
amountFromJson (SField::ref name, Json::Value const& v);
STAmount
amountFromRate (std::uint64_t uRate);
bool
amountFromJsonNoThrow (STAmount& result, Json::Value const& jvSource);

View File

@@ -224,9 +224,17 @@ inline bool isTecClaim(TER x)
}
// VFALCO TODO group these into a shell class along with the defines above.
extern bool transResultInfo (TER terCode, std::string& strToken, std::string& strHuman);
extern std::string transToken (TER terCode);
extern std::string transHuman (TER terCode);
extern
bool
transResultInfo (TER code, std::string& token, std::string& text);
extern
std::string
transToken (TER code);
extern
std::string
transHuman (TER code);
} // ripple

View File

@@ -83,8 +83,6 @@ std::string to_string(Account const&);
/** Returns "", "XRP", or three letter ISO code. */
std::string to_string(Currency const& c);
const char* systemCurrencyCode();
/** Tries to convert a string to a Currency, returns true on success. */
bool to_currency(Currency&, std::string const&);

View File

@@ -851,6 +851,12 @@ void STAmount::set (std::int64_t v)
//------------------------------------------------------------------------------
STAmount
amountFromRate (std::uint64_t uRate)
{
return STAmount (noIssue(), uRate, -9, false);
}
STAmount
amountFromQuality (std::uint64_t rate)
{
@@ -1135,7 +1141,6 @@ operator- (STAmount const& value)
//
//------------------------------------------------------------------------------
// NIKB TODO Make Amount::divide skip math if den == QUALITY_ONE
STAmount
divide (STAmount const& num, STAmount const& den, Issue const& issue)
{

View File

@@ -17,144 +17,148 @@
*/
//==============================================================================
#include <ripple/basics/ArraySize.h>
#include <ripple/protocol/TER.h>
namespace ripple {
bool transResultInfo (TER terCode, std::string& strToken, std::string& strHuman)
bool transResultInfo (TER code, std::string& token, std::string& text)
{
static struct
struct TxResultInfo
{
TER terCode;
const char* cpToken;
const char* cpHuman;
} transResultInfoA[] =
{
{ tecCLAIM, "tecCLAIM", "Fee claimed. Sequence used. No action." },
{ tecDIR_FULL, "tecDIR_FULL", "Can not add entry to full directory." },
{ tecFAILED_PROCESSING, "tecFAILED_PROCESSING", "Failed to correctly process transaction." },
{ tecINSUF_RESERVE_LINE, "tecINSUF_RESERVE_LINE", "Insufficient reserve to add trust line." },
{ tecINSUF_RESERVE_OFFER, "tecINSUF_RESERVE_OFFER", "Insufficient reserve to create offer." },
{ tecNO_DST, "tecNO_DST", "Destination does not exist. Send XRP to create it." },
{ tecNO_DST_INSUF_XRP, "tecNO_DST_INSUF_XRP", "Destination does not exist. Too little XRP sent to create it." },
{ tecNO_LINE_INSUF_RESERVE, "tecNO_LINE_INSUF_RESERVE", "No such line. Too little reserve to create it." },
{ tecNO_LINE_REDUNDANT, "tecNO_LINE_REDUNDANT", "Can't set non-existent line to default." },
{ tecPATH_DRY, "tecPATH_DRY", "Path could not send partial amount." },
{ tecPATH_PARTIAL, "tecPATH_PARTIAL", "Path could not send full amount." },
{ tecMASTER_DISABLED, "tecMASTER_DISABLED", "Master key is disabled." },
{ tecNO_REGULAR_KEY, "tecNO_REGULAR_KEY", "Regular key is not set." },
{ tecUNFUNDED, "tecUNFUNDED", "One of _ADD, _OFFER, or _SEND. Deprecated." },
{ tecUNFUNDED_ADD, "tecUNFUNDED_ADD", "Insufficient XRP balance for WalletAdd." },
{ tecUNFUNDED_OFFER, "tecUNFUNDED_OFFER", "Insufficient balance to fund created offer." },
{ tecUNFUNDED_PAYMENT, "tecUNFUNDED_PAYMENT", "Insufficient XRP balance to send." },
{ tecOWNERS, "tecOWNERS", "Non-zero owner count." },
{ tecNO_ISSUER, "tecNO_ISSUER", "Issuer account does not exist." },
{ tecNO_AUTH, "tecNO_AUTH", "Not authorized to hold asset." },
{ tecNO_LINE, "tecNO_LINE", "No such line." },
{ tecINSUFF_FEE, "tecINSUFF_FEE", "Insufficient balance to pay fee." },
{ tecFROZEN, "tecFROZEN", "Asset is frozen." },
{ tecNO_TARGET, "tecNO_TARGET", "Target account does not exist." },
{ tecNO_PERMISSION, "tecNO_PERMISSION", "No permission to perform requested operation." },
{ tecNO_ENTRY, "tecNO_ENTRY", "No matching entry found." },
{ tecINSUFFICIENT_RESERVE,"tecINSUFFICIENT_RESERVE", "Insufficient reserve to complete requested operation." },
{ tefALREADY, "tefALREADY", "The exact transaction was already in this ledger." },
{ tefBAD_ADD_AUTH, "tefBAD_ADD_AUTH", "Not authorized to add account." },
{ tefBAD_AUTH, "tefBAD_AUTH", "Transaction's public key is not authorized." },
{ tefBAD_LEDGER, "tefBAD_LEDGER", "Ledger in unexpected state." },
{ tefCREATED, "tefCREATED", "Can't add an already created account." },
{ tefDST_TAG_NEEDED, "tefDST_TAG_NEEDED", "Destination tag required." },
{ tefEXCEPTION, "tefEXCEPTION", "Unexpected program state." },
{ tefFAILURE, "tefFAILURE", "Failed to apply." },
{ tefINTERNAL, "tefINTERNAL", "Internal error." },
{ tefMASTER_DISABLED, "tefMASTER_DISABLED", "Master key is disabled." },
{ tefMAX_LEDGER, "tefMAX_LEDGER", "Ledger sequence too high." },
{ tefNO_AUTH_REQUIRED, "tefNO_AUTH_REQUIRED", "Auth is not required." },
{ tefPAST_SEQ, "tefPAST_SEQ", "This sequence number has already past." },
{ tefWRONG_PRIOR, "tefWRONG_PRIOR", "This previous transaction does not match." },
{ telLOCAL_ERROR, "telLOCAL_ERROR", "Local failure." },
{ telBAD_DOMAIN, "telBAD_DOMAIN", "Domain too long." },
{ telBAD_PATH_COUNT, "telBAD_PATH_COUNT", "Malformed: Too many paths." },
{ telBAD_PUBLIC_KEY, "telBAD_PUBLIC_KEY", "Public key too long." },
{ telFAILED_PROCESSING, "telFAILED_PROCESSING", "Failed to correctly process transaction." },
{ telINSUF_FEE_P, "telINSUF_FEE_P", "Fee insufficient." },
{ telNO_DST_PARTIAL, "telNO_DST_PARTIAL", "Partial payment to create account not allowed." },
{ temMALFORMED, "temMALFORMED", "Malformed transaction." },
{ temBAD_AMOUNT, "temBAD_AMOUNT", "Can only send positive amounts." },
{ temBAD_AUTH_MASTER, "temBAD_AUTH_MASTER", "Auth for unclaimed account needs correct master key." },
{ temBAD_CURRENCY, "temBAD_CURRENCY", "Malformed: Bad currency." },
{ temBAD_EXPIRATION, "temBAD_EXPIRATION", "Malformed: Bad expiration." },
{ temBAD_FEE, "temBAD_FEE", "Invalid fee, negative or not XRP." },
{ temBAD_ISSUER, "temBAD_ISSUER", "Malformed: Bad issuer." },
{ temBAD_LIMIT, "temBAD_LIMIT", "Limits must be non-negative." },
{ temBAD_OFFER, "temBAD_OFFER", "Malformed: Bad offer." },
{ temBAD_PATH, "temBAD_PATH", "Malformed: Bad path." },
{ temBAD_PATH_LOOP, "temBAD_PATH_LOOP", "Malformed: Loop in path." },
{ temBAD_SEND_XRP_LIMIT, "temBAD_SEND_XRP_LIMIT", "Malformed: Limit quality is not allowed for XRP to XRP." },
{ temBAD_SEND_XRP_MAX, "temBAD_SEND_XRP_MAX", "Malformed: Send max is not allowed for XRP to XRP." },
{ temBAD_SEND_XRP_NO_DIRECT, "temBAD_SEND_XRP_NO_DIRECT", "Malformed: No Ripple direct is not allowed for XRP to XRP." },
{ temBAD_SEND_XRP_PARTIAL, "temBAD_SEND_XRP_PARTIAL", "Malformed: Partial payment is not allowed for XRP to XRP." },
{ temBAD_SEND_XRP_PATHS, "temBAD_SEND_XRP_PATHS", "Malformed: Paths are not allowed for XRP to XRP." },
{ temBAD_SEQUENCE, "temBAD_SEQUENCE", "Malformed: Sequence is not in the past." },
{ temBAD_SIGNATURE, "temBAD_SIGNATURE", "Malformed: Bad signature." },
{ temBAD_SRC_ACCOUNT, "temBAD_SRC_ACCOUNT", "Malformed: Bad source account." },
{ temBAD_TRANSFER_RATE, "temBAD_TRANSFER_RATE", "Malformed: Transfer rate must be >= 1.0" },
{ temDST_IS_SRC, "temDST_IS_SRC", "Destination may not be source." },
{ temDST_NEEDED, "temDST_NEEDED", "Destination not specified." },
{ temINVALID, "temINVALID", "The transaction is ill-formed." },
{ temINVALID_FLAG, "temINVALID_FLAG", "The transaction has an invalid flag." },
{ temREDUNDANT, "temREDUNDANT", "Sends same currency to self." },
{ temREDUNDANT_SEND_MAX, "temREDUNDANT_SEND_MAX", "Send max is redundant." },
{ temRIPPLE_EMPTY, "temRIPPLE_EMPTY", "PathSet with no paths." },
{ temUNCERTAIN, "temUNCERTAIN", "In process of determining result. Never returned." },
{ temUNKNOWN, "temUNKNOWN", "The transactions requires logic not implemented yet." },
{ terRETRY, "terRETRY", "Retry transaction." },
{ terFUNDS_SPENT, "terFUNDS_SPENT", "Can't set password, password set funds already spent." },
{ terINSUF_FEE_B, "terINSUF_FEE_B", "Account balance can't pay fee." },
{ terLAST, "terLAST", "Process last." },
{ terNO_RIPPLE, "terNO_RIPPLE", "Path does not permit rippling." },
{ terNO_ACCOUNT, "terNO_ACCOUNT", "The source account does not exist." },
{ terNO_AUTH, "terNO_AUTH", "Not authorized to hold IOUs." },
{ terNO_LINE, "terNO_LINE", "No such line." },
{ terPRE_SEQ, "terPRE_SEQ", "Missing/inapplicable prior transaction." },
{ terOWNERS, "terOWNERS", "Non-zero owner count." },
{ tesSUCCESS, "tesSUCCESS", "The transaction was applied. Only final in a validated ledger." },
TER code;
char const* token;
char const* text;
};
int iIndex = RIPPLE_ARRAYSIZE (transResultInfoA);
while (iIndex-- && transResultInfoA[iIndex].terCode != terCode)
;
if (iIndex >= 0)
// FIXME: replace this with a function-static std::map and the lookup
// code with std::map::find when the problem with magic statics on
// Visual Studio is fixed.
static
TxResultInfo const results[] =
{
strToken = transResultInfoA[iIndex].cpToken;
strHuman = transResultInfoA[iIndex].cpHuman;
{ tecCLAIM, "tecCLAIM", "Fee claimed. Sequence used. No action." },
{ tecDIR_FULL, "tecDIR_FULL", "Can not add entry to full directory." },
{ tecFAILED_PROCESSING, "tecFAILED_PROCESSING", "Failed to correctly process transaction." },
{ tecINSUF_RESERVE_LINE, "tecINSUF_RESERVE_LINE", "Insufficient reserve to add trust line." },
{ tecINSUF_RESERVE_OFFER, "tecINSUF_RESERVE_OFFER", "Insufficient reserve to create offer." },
{ tecNO_DST, "tecNO_DST", "Destination does not exist. Send XRP to create it." },
{ tecNO_DST_INSUF_XRP, "tecNO_DST_INSUF_XRP", "Destination does not exist. Too little XRP sent to create it." },
{ tecNO_LINE_INSUF_RESERVE, "tecNO_LINE_INSUF_RESERVE", "No such line. Too little reserve to create it." },
{ tecNO_LINE_REDUNDANT, "tecNO_LINE_REDUNDANT", "Can't set non-existent line to default." },
{ tecPATH_DRY, "tecPATH_DRY", "Path could not send partial amount." },
{ tecPATH_PARTIAL, "tecPATH_PARTIAL", "Path could not send full amount." },
{ tecMASTER_DISABLED, "tecMASTER_DISABLED", "Master key is disabled." },
{ tecNO_REGULAR_KEY, "tecNO_REGULAR_KEY", "Regular key is not set." },
{ tecUNFUNDED, "tecUNFUNDED", "One of _ADD, _OFFER, or _SEND. Deprecated." },
{ tecUNFUNDED_ADD, "tecUNFUNDED_ADD", "Insufficient XRP balance for WalletAdd." },
{ tecUNFUNDED_OFFER, "tecUNFUNDED_OFFER", "Insufficient balance to fund created offer." },
{ tecUNFUNDED_PAYMENT, "tecUNFUNDED_PAYMENT", "Insufficient XRP balance to send." },
{ tecOWNERS, "tecOWNERS", "Non-zero owner count." },
{ tecNO_ISSUER, "tecNO_ISSUER", "Issuer account does not exist." },
{ tecNO_AUTH, "tecNO_AUTH", "Not authorized to hold asset." },
{ tecNO_LINE, "tecNO_LINE", "No such line." },
{ tecINSUFF_FEE, "tecINSUFF_FEE", "Insufficient balance to pay fee." },
{ tecFROZEN, "tecFROZEN", "Asset is frozen." },
{ tecNO_TARGET, "tecNO_TARGET", "Target account does not exist." },
{ tecNO_PERMISSION, "tecNO_PERMISSION", "No permission to perform requested operation." },
{ tecNO_ENTRY, "tecNO_ENTRY", "No matching entry found." },
{ tecINSUFFICIENT_RESERVE, "tecINSUFFICIENT_RESERVE", "Insufficient reserve to complete requested operation." },
{ tefALREADY, "tefALREADY", "The exact transaction was already in this ledger." },
{ tefBAD_ADD_AUTH, "tefBAD_ADD_AUTH", "Not authorized to add account." },
{ tefBAD_AUTH, "tefBAD_AUTH", "Transaction's public key is not authorized." },
{ tefBAD_LEDGER, "tefBAD_LEDGER", "Ledger in unexpected state." },
{ tefCREATED, "tefCREATED", "Can't add an already created account." },
{ tefDST_TAG_NEEDED, "tefDST_TAG_NEEDED", "Destination tag required." },
{ tefEXCEPTION, "tefEXCEPTION", "Unexpected program state." },
{ tefFAILURE, "tefFAILURE", "Failed to apply." },
{ tefINTERNAL, "tefINTERNAL", "Internal error." },
{ tefMASTER_DISABLED, "tefMASTER_DISABLED", "Master key is disabled." },
{ tefMAX_LEDGER, "tefMAX_LEDGER", "Ledger sequence too high." },
{ tefNO_AUTH_REQUIRED, "tefNO_AUTH_REQUIRED", "Auth is not required." },
{ tefPAST_SEQ, "tefPAST_SEQ", "This sequence number has already past." },
{ tefWRONG_PRIOR, "tefWRONG_PRIOR", "This previous transaction does not match." },
{ telLOCAL_ERROR, "telLOCAL_ERROR", "Local failure." },
{ telBAD_DOMAIN, "telBAD_DOMAIN", "Domain too long." },
{ telBAD_PATH_COUNT, "telBAD_PATH_COUNT", "Malformed: Too many paths." },
{ telBAD_PUBLIC_KEY, "telBAD_PUBLIC_KEY", "Public key too long." },
{ telFAILED_PROCESSING, "telFAILED_PROCESSING", "Failed to correctly process transaction." },
{ telINSUF_FEE_P, "telINSUF_FEE_P", "Fee insufficient." },
{ telNO_DST_PARTIAL, "telNO_DST_PARTIAL", "Partial payment to create account not allowed." },
{ temMALFORMED, "temMALFORMED", "Malformed transaction." },
{ temBAD_AMOUNT, "temBAD_AMOUNT", "Can only send positive amounts." },
{ temBAD_AUTH_MASTER, "temBAD_AUTH_MASTER", "Auth for unclaimed account needs correct master key." },
{ temBAD_CURRENCY, "temBAD_CURRENCY", "Malformed: Bad currency." },
{ temBAD_EXPIRATION, "temBAD_EXPIRATION", "Malformed: Bad expiration." },
{ temBAD_FEE, "temBAD_FEE", "Invalid fee, negative or not XRP." },
{ temBAD_ISSUER, "temBAD_ISSUER", "Malformed: Bad issuer." },
{ temBAD_LIMIT, "temBAD_LIMIT", "Limits must be non-negative." },
{ temBAD_OFFER, "temBAD_OFFER", "Malformed: Bad offer." },
{ temBAD_PATH, "temBAD_PATH", "Malformed: Bad path." },
{ temBAD_PATH_LOOP, "temBAD_PATH_LOOP", "Malformed: Loop in path." },
{ temBAD_SEND_XRP_LIMIT, "temBAD_SEND_XRP_LIMIT", "Malformed: Limit quality is not allowed for XRP to XRP." },
{ temBAD_SEND_XRP_MAX, "temBAD_SEND_XRP_MAX", "Malformed: Send max is not allowed for XRP to XRP." },
{ temBAD_SEND_XRP_NO_DIRECT,"temBAD_SEND_XRP_NO_DIRECT","Malformed: No Ripple direct is not allowed for XRP to XRP." },
{ temBAD_SEND_XRP_PARTIAL, "temBAD_SEND_XRP_PARTIAL", "Malformed: Partial payment is not allowed for XRP to XRP." },
{ temBAD_SEND_XRP_PATHS, "temBAD_SEND_XRP_PATHS", "Malformed: Paths are not allowed for XRP to XRP." },
{ temBAD_SEQUENCE, "temBAD_SEQUENCE", "Malformed: Sequence is not in the past." },
{ temBAD_SIGNATURE, "temBAD_SIGNATURE", "Malformed: Bad signature." },
{ temBAD_SRC_ACCOUNT, "temBAD_SRC_ACCOUNT", "Malformed: Bad source account." },
{ temBAD_TRANSFER_RATE, "temBAD_TRANSFER_RATE", "Malformed: Transfer rate must be >= 1.0" },
{ temDST_IS_SRC, "temDST_IS_SRC", "Destination may not be source." },
{ temDST_NEEDED, "temDST_NEEDED", "Destination not specified." },
{ temINVALID, "temINVALID", "The transaction is ill-formed." },
{ temINVALID_FLAG, "temINVALID_FLAG", "The transaction has an invalid flag." },
{ temREDUNDANT, "temREDUNDANT", "Sends same currency to self." },
{ temREDUNDANT_SEND_MAX, "temREDUNDANT_SEND_MAX", "Send max is redundant." },
{ temRIPPLE_EMPTY, "temRIPPLE_EMPTY", "PathSet with no paths." },
{ temUNCERTAIN, "temUNCERTAIN", "In process of determining result. Never returned." },
{ temUNKNOWN, "temUNKNOWN", "The transactions requires logic not implemented yet." },
{ terRETRY, "terRETRY", "Retry transaction." },
{ terFUNDS_SPENT, "terFUNDS_SPENT", "Can't set password, password set funds already spent." },
{ terINSUF_FEE_B, "terINSUF_FEE_B", "Account balance can't pay fee." },
{ terLAST, "terLAST", "Process last." },
{ terNO_RIPPLE, "terNO_RIPPLE", "Path does not permit rippling." },
{ terNO_ACCOUNT, "terNO_ACCOUNT", "The source account does not exist." },
{ terNO_AUTH, "terNO_AUTH", "Not authorized to hold IOUs." },
{ terNO_LINE, "terNO_LINE", "No such line." },
{ terPRE_SEQ, "terPRE_SEQ", "Missing/inapplicable prior transaction." },
{ terOWNERS, "terOWNERS", "Non-zero owner count." },
{ tesSUCCESS, "tesSUCCESS", "The transaction was applied. Only final in a validated ledger." },
};
for (auto const& result : results)
{
if (result.code == code)
{
token = result.token;
text = result.text;
return true;
}
}
return iIndex >= 0;
return false;
}
std::string transToken (TER terCode)
std::string transToken (TER code)
{
std::string strToken;
std::string strHuman;
std::string token;
std::string text;
return transResultInfo (terCode, strToken, strHuman) ? strToken : "-";
return transResultInfo (code, token, text) ? token : "-";
}
std::string transHuman (TER terCode)
std::string transHuman (TER code)
{
std::string strToken;
std::string strHuman;
std::string token;
std::string text;
return transResultInfo (terCode, strToken, strHuman) ? strHuman : "-";
return transResultInfo (code, token, text) ? text : "-";
}
} // ripple

View File

@@ -17,6 +17,7 @@
*/
//==============================================================================
#include <ripple/core/SystemParameters.h>
#include <ripple/protocol/RippleAddress.h>
#include <ripple/protocol/UintTypes.h>
@@ -120,10 +121,6 @@ bool to_issuer(Account& issuer, std::string const& s)
return success;
}
const char* systemCurrencyCode() {
return "XRP";
}
Account const& xrpAccount()
{
static Account const account(0);

View File

@@ -25,7 +25,7 @@ Json::Value doStop (RPC::Context& context)
auto lock = getApp().masterLock();
getApp().signalStop ();
return RPC::makeObjectValue (SYSTEM_NAME " server stopping");
return RPC::makeObjectValue (systemName () + " server stopping");
}
} // ripple

View File

@@ -17,7 +17,6 @@
*/
//==============================================================================
#include <ripple/basics/ArraySize.h>
#include <ripple/rpc/impl/JsonWriter.h>
#include <beast/unit_test/suite.h>

View File

@@ -73,7 +73,7 @@ std::string HTTPReply (int nStatus, std::string const& strMsg)
// CHECKME this returns a different version than the replies below. Is
// this by design or an accident or should it be using
// BuildInfo::getFullVersionString () as well?
ret.append ("Server: " SYSTEM_NAME "-json-rpc/v1");
ret.append ("Server: " + systemName () + "-json-rpc/v1");
ret.append ("\r\n");
// Be careful in modifying this! If you change the contents you MUST
@@ -120,7 +120,7 @@ std::string HTTPReply (int nStatus, std::string const& strMsg)
ret.append ("Content-Type: application/json; charset=UTF-8\r\n");
ret.append ("Server: " SYSTEM_NAME "-json-rpc/");
ret.append ("Server: " + systemName () + "-json-rpc/");
ret.append (BuildInfo::getFullVersionString ());
ret.append ("\r\n");

View File

@@ -38,5 +38,3 @@
#include <ripple/basics/impl/make_SSLContext.cpp>
#include <ripple/basics/impl/ResolverAsio.cpp>
#include <ripple/basics/impl/TaggedCache.cpp>
#include <ripple/basics/tests/cross_offer.test.cpp>