mirror of
https://github.com/XRPLF/rippled.git
synced 2025-11-18 18:15:50 +00:00
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:
@@ -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">
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -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:" <<
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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 ())
|
||||
|
||||
@@ -205,7 +205,7 @@ TER PathCursor::reverseLiquidityForAccount () const
|
||||
<< " (available) previousNode.saRevRedeem="
|
||||
<< previousNode().saRevRedeem
|
||||
<< " uRateMax="
|
||||
<< STAmount::saFromRate (uRateMax).getText ();
|
||||
<< amountFromRate (uRateMax).getText ();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -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_;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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&);
|
||||
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include <ripple/basics/ArraySize.h>
|
||||
#include <ripple/rpc/impl/JsonWriter.h>
|
||||
#include <beast/unit_test/suite.h>
|
||||
|
||||
|
||||
@@ -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");
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user