mirror of
https://github.com/XRPLF/rippled.git
synced 2025-12-05 16:57:56 +00:00
Merge branch 'master' of https://github.com/jedmccaleb/NewCoin into new_pathfinding
Conflicts: src/cpp/ripple/Application.cpp src/cpp/ripple/Pathfinder.cpp Merge.
This commit is contained in:
@@ -106,7 +106,7 @@ env.Append(LINKFLAGS = ['-rdynamic', '-pthread'])
|
||||
env.Append(CCFLAGS = ['-pthread', '-Wall', '-Wno-sign-compare', '-Wno-char-subscripts', '-DSQLITE_THREADSAFE=1'])
|
||||
env.Append(CXXFLAGS = ['-O0', '-pthread', '-Wno-invalid-offsetof', '-Wformat']+BOOSTFLAGS+DEBUGFLAGS)
|
||||
|
||||
if (GCC_VERSION[0] > 4 or (GCC_VERSION[0] == 4 and GCC_VERSION[1] >= 7)):
|
||||
if (int(GCC_VERSION[0]) > 4 or (int(GCC_VERSION[0]) == 4 and int(GCC_VERSION[1]) >= 7)):
|
||||
env.Append(CXXFLAGS = ['-std=c++11'])
|
||||
|
||||
if OSX:
|
||||
|
||||
@@ -101,6 +101,7 @@
|
||||
<ClCompile Include="src\cpp\ripple\AccountSetTransactor.cpp" />
|
||||
<ClCompile Include="src\cpp\ripple\AccountState.cpp" />
|
||||
<ClCompile Include="src\cpp\ripple\Amount.cpp" />
|
||||
<ClCompile Include="src\cpp\ripple\AmountRound.cpp" />
|
||||
<ClCompile Include="src\cpp\ripple\Application.cpp" />
|
||||
<ClCompile Include="src\cpp\ripple\BitcoinUtil.cpp" />
|
||||
<ClCompile Include="src\cpp\ripple\CallRPC.cpp" />
|
||||
@@ -175,6 +176,7 @@
|
||||
<ClCompile Include="src\cpp\ripple\Suppression.cpp" />
|
||||
<ClCompile Include="src\cpp\ripple\Transaction.cpp" />
|
||||
<ClCompile Include="src\cpp\ripple\TransactionAcquire.cpp" />
|
||||
<ClCompile Include="src\cpp\ripple\TransactionCheck.cpp" />
|
||||
<ClCompile Include="src\cpp\ripple\TransactionEngine.cpp" />
|
||||
<ClCompile Include="src\cpp\ripple\TransactionErr.cpp" />
|
||||
<ClCompile Include="src\cpp\ripple\TransactionFormats.cpp" />
|
||||
|
||||
@@ -249,6 +249,9 @@
|
||||
<ClCompile Include="src\cpp\ripple\TransactionEngine.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\cpp\ripple\TransactionCheck.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\cpp\ripple\TransactionErr.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
@@ -363,6 +366,9 @@
|
||||
<ClCompile Include="src\cpp\ripple\RPCSub.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\cpp\ripple\AmountRound.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="util\pugiconfig.hpp">
|
||||
|
||||
@@ -175,6 +175,7 @@
|
||||
<ClCompile Include="src\cpp\ripple\Suppression.cpp" />
|
||||
<ClCompile Include="src\cpp\ripple\Transaction.cpp" />
|
||||
<ClCompile Include="src\cpp\ripple\TransactionAcquire.cpp" />
|
||||
<ClCompile Include="src\cpp\ripple\TransactionCheck.cpp" />
|
||||
<ClCompile Include="src\cpp\ripple\TransactionEngine.cpp" />
|
||||
<ClCompile Include="src\cpp\ripple\TransactionErr.cpp" />
|
||||
<ClCompile Include="src\cpp\ripple\TransactionFormats.cpp" />
|
||||
|
||||
@@ -243,6 +243,9 @@
|
||||
<ClCompile Include="src\cpp\ripple\TransactionAcquire.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\cpp\ripple\TransactionCheck.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\cpp\ripple\TransactionEngine.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
#
|
||||
# Example: debug.log
|
||||
#
|
||||
# [validators]:
|
||||
# [validators]
|
||||
# List of nodes to always accept as validators. Nodes are specified by domain
|
||||
# or public key.
|
||||
#
|
||||
@@ -32,7 +32,7 @@
|
||||
# n9KorY8QtTdRx7TVDpwnG9NvyxsDwHUKUEeDLY3AkiGncVaSXZi5
|
||||
# n9MqiExBcoG19UXwoLjBJnhsxEhAZMuWwJDRdkyDz1EkEkwzQTNt John Doe
|
||||
#
|
||||
# [validators_file]:
|
||||
# [validators_file]
|
||||
# Path to file contain a list of nodes to always accept as validators. Use
|
||||
# this to specify a file other than this file to manage your validators list.
|
||||
#
|
||||
@@ -51,13 +51,13 @@
|
||||
# C:/home/johndoe/ripple/validators.txt
|
||||
# /home/johndoe/ripple/validators.txt
|
||||
#
|
||||
# [validators_site]:
|
||||
# [validators_site]
|
||||
# Specifies where to find validators.txt for UNL boostrapping and RPC
|
||||
# unl_network command.
|
||||
#
|
||||
# Example: ripple.com
|
||||
#
|
||||
# [ips]:
|
||||
# [ips]
|
||||
# List of ips where the Ripple protocol is served. For a starter list, you
|
||||
# can copy entries from: https://ripple.com/ripple.txt
|
||||
#
|
||||
@@ -80,38 +80,38 @@
|
||||
# time.nist.gov
|
||||
# pool.ntp.org
|
||||
#
|
||||
# [peer_ip]:
|
||||
# [peer_ip]
|
||||
# IP address or domain to bind to allow external connections from peers.
|
||||
# Defaults to not binding, which disallows external connections from peers.
|
||||
#
|
||||
# Examples: 0.0.0.0 - Bind on all interfaces.
|
||||
#
|
||||
# [peer_port]:
|
||||
# [peer_port]
|
||||
# If peer_ip is supplied, corresponding port to bind to for peer connections.
|
||||
#
|
||||
# [peer_private]:
|
||||
# [peer_private]
|
||||
# 0 or 1.
|
||||
# 0: request peers to broadcast your address. [default]
|
||||
# 1: request peers not broadcast your address.
|
||||
#
|
||||
# [rpc_ip]:
|
||||
# [rpc_ip]
|
||||
# IP address or domain to bind to allow insecure RPC connections.
|
||||
# Defaults to not binding, which disallows RPC connections.
|
||||
#
|
||||
# [rpc_port]:
|
||||
# [rpc_port]
|
||||
# If rpc_ip is supplied, corresponding port to bind to for peer connections.
|
||||
#
|
||||
# [rpc_allow_remote]:
|
||||
# [rpc_allow_remote]
|
||||
# 0 or 1.
|
||||
# 0: Allow RPC connections only from 127.0.0.1. [default]
|
||||
# 1: Allow RPC connections from any IP.
|
||||
#
|
||||
# [rpc_admin_allow]:
|
||||
# [rpc_admin_allow]
|
||||
# Specify an list of IP addresses allowed to have admin access. One per line.
|
||||
#
|
||||
# Defaults to 127.0.0.1.
|
||||
#
|
||||
# [rpc_user]:
|
||||
# [rpc_user]
|
||||
# As a server, require a this user to specified and require rpc_password to
|
||||
# be checked for RPC access via the rpc_ip and rpc_port. The user and password
|
||||
# must be specified via HTTP's basic authentication method.
|
||||
@@ -119,7 +119,7 @@
|
||||
# As a client, supply this to the server via HTTP's basic authentication
|
||||
# method.
|
||||
#
|
||||
# [rpc_password]:
|
||||
# [rpc_password]
|
||||
# As a server, require a this password to specified and require rpc_user to
|
||||
# be checked for RPC access via the rpc_ip and rpc_port. The user and password
|
||||
# must be specified via HTTP's basic authentication method.
|
||||
@@ -127,7 +127,7 @@
|
||||
# As a client, supply this to the server via HTTP's basic authentication
|
||||
# method.
|
||||
#
|
||||
# [rpc_admin_user]:
|
||||
# [rpc_admin_user]
|
||||
# As a server, require this as the admin user to be specified. Also, require
|
||||
# rpc_admin_user and rpc_admin_password to be checked for RPC admin functions.
|
||||
# The request must specify these as the admin_user and admin_password in the
|
||||
@@ -135,7 +135,7 @@
|
||||
#
|
||||
# As a client, supply this to the server in the request object.
|
||||
#
|
||||
# [rpc_admin_password]:
|
||||
# [rpc_admin_password]
|
||||
# As a server, require this as the admin pasword to be specified. Also,
|
||||
# require rpc_admin_user and rpc_admin_password to be checked for RPC admin
|
||||
# functions. The request must specify these as the admin_user and
|
||||
@@ -143,12 +143,12 @@
|
||||
#
|
||||
# As a client, supply this to the server in the request object.
|
||||
#
|
||||
# [validation_quorum]:
|
||||
# [validation_quorum]
|
||||
# Sets the minimum number of trusted validations a ledger must have before
|
||||
# the server considers it fully validated. Note that if you are validating,
|
||||
# your validation counts.
|
||||
#
|
||||
# [websocket_public_ip]:
|
||||
# [websocket_public_ip]
|
||||
# IP address or domain to bind to allow untrusted connections from clients.
|
||||
# In the future, this option will go away and the peer_ip will accept
|
||||
# websocket client connections.
|
||||
@@ -156,7 +156,7 @@
|
||||
# Examples: 0.0.0.0 - Bind on all interfaces.
|
||||
# 127.0.0.1 - Bind on localhost interface. Only local programs may connect.
|
||||
#
|
||||
# [websocket_public_port]:
|
||||
# [websocket_public_port]
|
||||
# Port to bind to allow untrusted connections from clients. In the future,
|
||||
# this option will go away and the peer_ip will accept websocket client
|
||||
# connections.
|
||||
@@ -172,14 +172,14 @@
|
||||
# reference client currently shares secrets with its server, this should be
|
||||
# enabled.
|
||||
#
|
||||
# [websocket_ip]:
|
||||
# [websocket_ip]
|
||||
# IP address or domain to bind to allow trusted ADMIN connections from backend
|
||||
# applications.
|
||||
#
|
||||
# Examples: 0.0.0.0 - Bind on all interfaces.
|
||||
# 127.0.0.1 - Bind on localhost interface. Only local programs may connect.
|
||||
#
|
||||
# [websocket_port]:
|
||||
# [websocket_port]
|
||||
# Port to bind to allow trusted ADMIN connections from backend applications.
|
||||
#
|
||||
# [websocket_secure]
|
||||
@@ -188,14 +188,14 @@
|
||||
# 1: Provide ws and wss service for websocket_ip/websocket_port
|
||||
# 2: Provide wss service for websocket_ip/websocket_port.
|
||||
#
|
||||
# [websocket_ssl_key]:
|
||||
# [websocket_ssl_key]
|
||||
# Specify the filename holding the SSL key in PEM format.
|
||||
#
|
||||
# [websocket_ssl_cert]:
|
||||
# [websocket_ssl_cert]
|
||||
# Specify the path to the SSL certificate file in PEM format.
|
||||
# This is not needed if the chain includes it.
|
||||
#
|
||||
# [websocket_ssl_chain]:
|
||||
# [websocket_ssl_chain]
|
||||
# If you need a certificate chain, specify the path to the certificate chain
|
||||
# here. The chain may include the end certificate.
|
||||
#
|
||||
@@ -205,7 +205,7 @@
|
||||
# that the server will accept for verifying HTTP servers. Used only for
|
||||
# outbound HTTPS client connections.
|
||||
#
|
||||
# [validation_seed]:
|
||||
# [validation_seed]
|
||||
# To perform validation, this section should contain either a validation seed
|
||||
# or key. The validation seed is used to generate the validation
|
||||
# public/private key pair. To obtain a validation seed, use the
|
||||
@@ -214,7 +214,7 @@
|
||||
# Examples: RASH BUSH MILK LOOK BAD BRIM AVID GAFF BAIT ROT POD LOVE
|
||||
# shfArahZT9Q9ckTf3s1psJ7C7qzVN
|
||||
#
|
||||
# [node_seed]:
|
||||
# [node_seed]
|
||||
# This is used for clustering. To force a particular node seed or key, the
|
||||
# key can be set here. The format is the same as the validation_seed field.
|
||||
# To obtain a validation seed, use the validation_create command.
|
||||
@@ -222,19 +222,19 @@
|
||||
# Examples: RASH BUSH MILK LOOK BAD BRIM AVID GAFF BAIT ROT POD LOVE
|
||||
# shfArahZT9Q9ckTf3s1psJ7C7qzVN
|
||||
#
|
||||
# [node_size]:
|
||||
# [node_size]
|
||||
# Tunes the servers based on the expected load and available memory. Legal
|
||||
# sizes are "tiny", "small", "medium", "large", and "huge". We recommend
|
||||
# you start at the default and raise the setting if you have extra memory.
|
||||
# The default is "tiny".
|
||||
#
|
||||
# [cluster_nodes]:
|
||||
# [cluster_nodes]
|
||||
# To extend full trust to other nodes, place their node public keys here.
|
||||
# Generally, you should only do this for nodes under common administration.
|
||||
# Node public keys start with an 'n'. To give a node a name for identification
|
||||
# place a space after the public key and then the name.
|
||||
#
|
||||
# [ledger_history]:
|
||||
# [ledger_history]
|
||||
# The number of past ledgers to acquire on server startup and the minimum to
|
||||
# maintain while running.
|
||||
#
|
||||
@@ -244,7 +244,7 @@
|
||||
#
|
||||
# The default is: 256
|
||||
#
|
||||
# [database_path]:
|
||||
# [database_path]
|
||||
# Full path of database directory.
|
||||
#
|
||||
# [path_search_size]
|
||||
@@ -253,10 +253,12 @@
|
||||
#
|
||||
# The default is: 5
|
||||
#
|
||||
# [rpc_startup]:
|
||||
# [rpc_startup]
|
||||
# Specify a list of RPC commands to run at startup.
|
||||
#
|
||||
# Example: { "command" : "server_info" }
|
||||
# Examples:
|
||||
# { "command" : "server_info" }
|
||||
# { "command" : "log_level", "partition" : "ripplecalc", "severity" : "trace" }
|
||||
#
|
||||
|
||||
# Allow other peers to connect to this server.
|
||||
|
||||
@@ -100,8 +100,7 @@ public:
|
||||
|
||||
static ValueAllocator *&valueAllocator()
|
||||
{
|
||||
static DefaultValueAllocator defaultAllocator;
|
||||
static ValueAllocator *valueAllocator = &defaultAllocator;
|
||||
static ValueAllocator *valueAllocator = new DefaultValueAllocator;
|
||||
return valueAllocator;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <limits.h>
|
||||
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/regex.hpp>
|
||||
#include <boost/algorithm/string/split.hpp>
|
||||
#include <boost/algorithm/string/classification.hpp>
|
||||
#include <boost/test/unit_test.hpp>
|
||||
@@ -257,134 +258,77 @@ std::string STAmount::createHumanCurrency(const uint160& uCurrency)
|
||||
return sCurrency;
|
||||
}
|
||||
|
||||
// Assumes trusted input.
|
||||
bool STAmount::setValue(const std::string& sAmount)
|
||||
{ // Note: mIsNative and mCurrency must be set already!
|
||||
uint64 uValue;
|
||||
int iOffset;
|
||||
size_t uDecimal = sAmount.find_first_of(mIsNative ? "^" : ".");
|
||||
size_t uExp = uDecimal == std::string::npos ? sAmount.find_first_of("e") : std::string::npos;
|
||||
bool bInteger = uDecimal == std::string::npos && uExp == std::string::npos;
|
||||
|
||||
mIsNegative = false;
|
||||
if (bInteger)
|
||||
static boost::regex reNumber("\\`([+-]?)(\\d*)(\\.(\\d*))?([eE]([+-]?)(\\d+))?\\'");
|
||||
boost::smatch smMatch;
|
||||
|
||||
if (!boost::regex_match(sAmount, smMatch, reNumber))
|
||||
{
|
||||
// Integer input: does not necessarily mean native.
|
||||
cLog(lsWARNING) << "Number not valid: \"" << sAmount << "\"";
|
||||
return false;
|
||||
}
|
||||
|
||||
try
|
||||
// Match fields: 0 = whole input, 1 = sign, 2 = integer portion, 3 = whole fraction (with '.')
|
||||
// 4 = fraction (without '.'), 5 = whole exponent (with 'e'), 6 = exponent sign, 7 = exponent number
|
||||
|
||||
try
|
||||
{
|
||||
if ((smMatch[2].length() + smMatch[4].length()) > 18)
|
||||
{
|
||||
int64 a = sAmount.empty() ? 0 : lexical_cast_st<int64>(sAmount);
|
||||
if (a >= 0)
|
||||
{
|
||||
uValue = static_cast<uint64>(a);
|
||||
}
|
||||
else
|
||||
{
|
||||
uValue = static_cast<uint64>(-a);
|
||||
mIsNegative = true;
|
||||
}
|
||||
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
cLog(lsINFO) << "Bad integer amount: " << sAmount;
|
||||
|
||||
cLog(lsWARNING) << "Overlong number: " << sAmount;
|
||||
return false;
|
||||
}
|
||||
iOffset = 0;
|
||||
}
|
||||
else if (uExp != std::string::npos)
|
||||
{
|
||||
// e input
|
||||
|
||||
try
|
||||
mIsNegative = (smMatch[1].matched && (smMatch[1] == "-"));
|
||||
|
||||
if (!smMatch[4].matched) // integer only
|
||||
{
|
||||
int64 iInteger = uExp ? lexical_cast_st<uint64>(sAmount.substr(0, uExp)) : 0;
|
||||
if (iInteger >= 0)
|
||||
{
|
||||
uValue = static_cast<uint64>(iInteger);
|
||||
}
|
||||
mValue = lexical_cast_s<uint64>(smMatch[2]);
|
||||
mOffset = 0;
|
||||
}
|
||||
else
|
||||
{ // integer and fraction
|
||||
mValue = lexical_cast_s<uint64>(smMatch[2] + smMatch[4]);
|
||||
mOffset = -(smMatch[4].length());
|
||||
}
|
||||
|
||||
if (smMatch[5].matched)
|
||||
{ // we have an exponent
|
||||
if (smMatch[6].matched && (smMatch[6] == "-"))
|
||||
mOffset -= lexical_cast_s<int>(smMatch[7]);
|
||||
else
|
||||
{
|
||||
uValue = static_cast<uint64>(-iInteger);
|
||||
mIsNegative = true;
|
||||
}
|
||||
|
||||
iOffset = lexical_cast_st<uint64>(sAmount.substr(uExp+1));
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
cLog(lsINFO) << "Bad e amount: " << sAmount;
|
||||
|
||||
return false;
|
||||
mOffset += lexical_cast_s<int>(smMatch[7]);
|
||||
}
|
||||
}
|
||||
else
|
||||
catch (...)
|
||||
{
|
||||
// Float input: has a decimal
|
||||
|
||||
// Example size decimal size-decimal offset
|
||||
// ^1 2 0 2 -1
|
||||
// 123^ 4 3 1 0
|
||||
// 1^23 4 1 3 -2
|
||||
try
|
||||
{
|
||||
iOffset = -int(sAmount.size() - uDecimal - 1);
|
||||
|
||||
// Issolate integer and fraction.
|
||||
uint64 uInteger;
|
||||
int64 iInteger = uDecimal ? lexical_cast_st<uint64>(sAmount.substr(0, uDecimal)) : 0;
|
||||
if (iInteger >= 0)
|
||||
{
|
||||
uInteger = static_cast<uint64>(iInteger);
|
||||
}
|
||||
else
|
||||
{
|
||||
uInteger = static_cast<uint64>(-iInteger);
|
||||
mIsNegative = true;
|
||||
}
|
||||
|
||||
uint64 uFraction = iOffset ? lexical_cast_st<uint64>(sAmount.substr(uDecimal+1)) : 0;
|
||||
|
||||
// Scale the integer portion to the same offset as the fraction.
|
||||
uValue = uInteger;
|
||||
for (int i = -iOffset; i--;)
|
||||
uValue *= 10;
|
||||
|
||||
// Add in the fraction.
|
||||
uValue += uFraction;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
cLog(lsINFO) << "Bad float amount: " << sAmount;
|
||||
|
||||
return false;
|
||||
}
|
||||
cLog(lsWARNING) << "Number not parsed: \"" << sAmount << "\"";
|
||||
return false;
|
||||
}
|
||||
|
||||
cLog(lsTRACE) << "Float \"" << sAmount << "\" parsed to " << mValue << " : " << mOffset;
|
||||
|
||||
if (mIsNative)
|
||||
{
|
||||
if (bInteger)
|
||||
iOffset = -SYSTEM_CURRENCY_PRECISION;
|
||||
if (smMatch[3].matched)
|
||||
mOffset -= SYSTEM_CURRENCY_PRECISION;
|
||||
|
||||
while (iOffset > -SYSTEM_CURRENCY_PRECISION) {
|
||||
uValue *= 10;
|
||||
--iOffset;
|
||||
while (mOffset > 0)
|
||||
{
|
||||
mValue *= 10;
|
||||
--mOffset;
|
||||
}
|
||||
|
||||
while (iOffset < -SYSTEM_CURRENCY_PRECISION) {
|
||||
uValue /= 10;
|
||||
++iOffset;
|
||||
while (mOffset < 0) {
|
||||
mValue /= 10;
|
||||
++mOffset;
|
||||
}
|
||||
|
||||
mValue = uValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
mValue = uValue;
|
||||
mOffset = iOffset;
|
||||
canonicalize();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1287,11 +1231,13 @@ BOOST_AUTO_TEST_CASE( setValue_test )
|
||||
{
|
||||
STAmount saTmp;
|
||||
|
||||
#if 0
|
||||
// Check native floats
|
||||
saTmp.setFullValue("1^0"); BOOST_CHECK_MESSAGE(SYSTEM_CURRENCY_PARTS == saTmp.getNValue(), "float integer failed");
|
||||
saTmp.setFullValue("0^1"); BOOST_CHECK_MESSAGE(SYSTEM_CURRENCY_PARTS/10 == saTmp.getNValue(), "float fraction failed");
|
||||
saTmp.setFullValue("0^12"); BOOST_CHECK_MESSAGE(12*SYSTEM_CURRENCY_PARTS/100 == saTmp.getNValue(), "float fraction failed");
|
||||
saTmp.setFullValue("1^2"); BOOST_CHECK_MESSAGE(SYSTEM_CURRENCY_PARTS+(2*SYSTEM_CURRENCY_PARTS/10) == saTmp.getNValue(), "float combined failed");
|
||||
#endif
|
||||
|
||||
// Check native integer
|
||||
saTmp.setFullValue("1"); BOOST_CHECK_MESSAGE(1 == saTmp.getNValue(), "integer failed");
|
||||
|
||||
@@ -48,7 +48,8 @@ DatabaseCon::~DatabaseCon()
|
||||
Application::Application() :
|
||||
mIOWork(mIOService), mAuxWork(mAuxService), mUNL(mIOService), mNetOps(mIOService, &mLedgerMaster),
|
||||
mTempNodeCache("NodeCache", 16384, 90), mHashedObjectStore(16384, 300), mSLECache("LedgerEntryCache", 4096, 120),
|
||||
mSNTPClient(mAuxService), mFeeTrack(), mRpcDB(NULL), mTxnDB(NULL), mLedgerDB(NULL), mWalletDB(NULL),
|
||||
mSNTPClient(mAuxService), mJobQueue(mIOService), mFeeTrack(),
|
||||
mRpcDB(NULL), mTxnDB(NULL), mLedgerDB(NULL), mWalletDB(NULL),
|
||||
mHashNodeDB(NULL), mNetNodeDB(NULL), mPathFindDB(NULL),
|
||||
mConnectionPool(mIOService), mPeerDoor(NULL), mRPCDoor(NULL), mWSPublicDoor(NULL), mWSPrivateDoor(NULL),
|
||||
mSweepTimer(mAuxService), mShutdown(false)
|
||||
|
||||
@@ -134,72 +134,70 @@ Json::Value RPCParser::parseInternal(const Json::Value& jvParams)
|
||||
return v;
|
||||
}
|
||||
|
||||
// account_info <account>|<nickname>|<account_public_key>
|
||||
// account_info <seed>|<pass_phrase>|<key> [[<index>] <ledger>]
|
||||
Json::Value RPCParser::parseAccountInfo(const Json::Value& jvParams)
|
||||
{
|
||||
Json::Value jvRequest(Json::objectValue);
|
||||
std::string strIdent = jvParams[0u].asString();
|
||||
// YYY This could be more strict and report casting errors.
|
||||
int iIndex = 2 == jvParams.size() ? lexical_cast_s<int>(jvParams[1u].asString()) : 0;
|
||||
|
||||
RippleAddress raAddress;
|
||||
|
||||
if (!raAddress.setAccountPublic(strIdent) && !raAddress.setAccountID(strIdent) && !raAddress.setSeedGeneric(strIdent))
|
||||
return rpcError(rpcACT_MALFORMED);
|
||||
|
||||
jvRequest["ident"] = strIdent;
|
||||
jvRequest["account_index"] = iIndex;
|
||||
|
||||
if (jvParams.size() == 3 && !jvParseLedger(jvRequest, jvParams[2u].asString()))
|
||||
return rpcError(rpcLGR_IDX_MALFORMED);
|
||||
|
||||
return jvRequest;
|
||||
}
|
||||
|
||||
// account_tx <account> <minledger> <maxledger>
|
||||
// account_tx <account> <ledger>
|
||||
// account_tx <account> binary
|
||||
// account_tx <account> <minledger> <maxledger> binary
|
||||
// account_tx accountID [ledger_min [ledger_max [limit [offset]]]] [binary] [count] [descending]
|
||||
Json::Value RPCParser::parseAccountTransactions(const Json::Value& jvParams)
|
||||
{
|
||||
Json::Value jvRequest(Json::objectValue);
|
||||
RippleAddress raAccount;
|
||||
|
||||
unsigned size = jvParams.size();
|
||||
|
||||
if ((size > 1) && (jvParams[size - 1].asString() == "binary"))
|
||||
{
|
||||
jvRequest["binary"] = true;
|
||||
--size;
|
||||
}
|
||||
|
||||
if (size < 2 || size > 3)
|
||||
return rpcError(rpcINVALID_PARAMS);
|
||||
unsigned int iParams = jvParams.size();
|
||||
|
||||
if (!raAccount.setAccountID(jvParams[0u].asString()))
|
||||
return rpcError(rpcACT_MALFORMED);
|
||||
|
||||
// YYY This could be more strict and report casting errors.
|
||||
if (size == 2)
|
||||
jvRequest["account"] = raAccount.humanAccountID();
|
||||
|
||||
bool bDone = false;
|
||||
|
||||
while (!bDone && iParams >= 2) {
|
||||
if (jvParams[iParams-1].asString() == "binary")
|
||||
{
|
||||
jvRequest["binary"] = true;
|
||||
--iParams;
|
||||
}
|
||||
else if (jvParams[iParams-1].asString() == "count")
|
||||
{
|
||||
jvRequest["count"] = true;
|
||||
--iParams;
|
||||
}
|
||||
else if (jvParams[iParams-1].asString() == "descending")
|
||||
{
|
||||
jvRequest["descending"] = true;
|
||||
--iParams;
|
||||
}
|
||||
else
|
||||
{
|
||||
bDone = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (1 == iParams)
|
||||
{
|
||||
jvRequest["ledger"] = jvParams[1u].asUInt();
|
||||
nothing();
|
||||
}
|
||||
else if (2 == iParams)
|
||||
{
|
||||
if (!jvParseLedger(jvRequest, jvParams[1u].asString()))
|
||||
return jvRequest;
|
||||
}
|
||||
else
|
||||
{
|
||||
uint32 uLedgerMin = jvParams[1u].asUInt();
|
||||
uint32 uLedgerMax = jvParams[2u].asUInt();
|
||||
int64 uLedgerMin = jvParams[1u].asInt();
|
||||
int64 uLedgerMax = jvParams[2u].asInt();
|
||||
|
||||
if ((uLedgerMax < uLedgerMin) || (uLedgerMax == 0))
|
||||
if (uLedgerMax != -1 && uLedgerMax < uLedgerMin)
|
||||
{
|
||||
return rpcError(rpcLGR_IDXS_INVALID);
|
||||
}
|
||||
|
||||
jvRequest["ledger_min"] = uLedgerMin;
|
||||
jvRequest["ledger_max"] = uLedgerMax;
|
||||
}
|
||||
jvRequest["ledger_index_min"] = jvParams[1u].asInt();
|
||||
jvRequest["ledger_index_max"] = jvParams[2u].asInt();
|
||||
|
||||
jvRequest["account"] = raAccount.humanAccountID();
|
||||
if (iParams >= 4)
|
||||
jvRequest["limit"] = jvParams[3u].asInt();
|
||||
|
||||
if (iParams >= 5)
|
||||
jvRequest["offset"] = jvParams[4u].asInt();
|
||||
}
|
||||
|
||||
return jvRequest;
|
||||
}
|
||||
@@ -420,30 +418,34 @@ Json::Value RPCParser::parseLogLevel(const Json::Value& jvParams)
|
||||
}
|
||||
|
||||
// owner_info <account>|<nickname>|<account_public_key>
|
||||
// owner_info <seed>|<pass_phrase>|<key> [<index>]
|
||||
Json::Value RPCParser::parseOwnerInfo(const Json::Value& jvParams)
|
||||
{
|
||||
return parseAccountInfo(jvParams);
|
||||
}
|
||||
|
||||
// account_lines <account>|<nickname>|<account_public_key> [<index>]
|
||||
// account_offers <account>|<nickname>|<account_public_key> [<index>]
|
||||
// owner_info <seed>|<pass_phrase>|<key> [<ledfer>]
|
||||
// account_info <account>|<nickname>|<account_public_key>
|
||||
// account_info <seed>|<pass_phrase>|<key> [<ledger>]
|
||||
// account_lines <account>|<nickname>|<account_public_key> [<ledger>]
|
||||
// account_offers <account>|<nickname>|<account_public_key> [<ledger>]
|
||||
Json::Value RPCParser::parseAccountItems(const Json::Value& jvParams)
|
||||
{
|
||||
std::string strIdent = jvParams[0u].asString();
|
||||
bool bIndex = 2 == jvParams.size();
|
||||
int iIndex = bIndex ? lexical_cast_s<int>(jvParams[1u].asString()) : 0;
|
||||
// TODO: Get index from an alternate syntax: rXYZ:<index>
|
||||
int iIndex = 0;
|
||||
// int iIndex = jvParams.size() >= 2 ? lexical_cast_s<int>(jvParams[1u].asString()) : 0;
|
||||
|
||||
if (bIndex && !iIndex) // Don't send default.
|
||||
bIndex = false;
|
||||
RippleAddress raAddress;
|
||||
|
||||
if (!raAddress.setAccountPublic(strIdent) && !raAddress.setAccountID(strIdent) && !raAddress.setSeedGeneric(strIdent))
|
||||
return rpcError(rpcACT_MALFORMED);
|
||||
|
||||
// Get info on account.
|
||||
Json::Value jvRequest(Json::objectValue);
|
||||
|
||||
jvRequest["account"] = strIdent;
|
||||
if (bIndex)
|
||||
|
||||
if (iIndex)
|
||||
jvRequest["account_index"] = iIndex;
|
||||
|
||||
if (jvParams.size() == 2 && !jvParseLedger(jvRequest, jvParams[1u].asString()))
|
||||
return rpcError(rpcLGR_IDX_MALFORMED);
|
||||
|
||||
return jvRequest;
|
||||
}
|
||||
|
||||
@@ -456,13 +458,13 @@ Json::Value RPCParser::parseRipplePathFind(const Json::Value& jvParams)
|
||||
|
||||
cLog(lsTRACE) << "RPC json: " << jvParams[0u];
|
||||
|
||||
if (bLedger)
|
||||
{
|
||||
jvParseLedger(jvRequest, jvParams[1u].asString());
|
||||
}
|
||||
|
||||
if (reader.parse(jvParams[0u].asString(), jvRequest))
|
||||
{
|
||||
if (bLedger)
|
||||
{
|
||||
jvParseLedger(jvRequest, jvParams[1u].asString());
|
||||
}
|
||||
|
||||
return jvRequest;
|
||||
}
|
||||
|
||||
@@ -642,10 +644,10 @@ Json::Value RPCParser::parseCommand(std::string strMethod, Json::Value jvParams)
|
||||
// Request-response methods
|
||||
// - Returns an error, or the request.
|
||||
// - To modify the method, provide a new method in the request.
|
||||
{ "account_info", &RPCParser::parseAccountInfo, 1, 3 },
|
||||
{ "account_info", &RPCParser::parseAccountItems, 1, 2 },
|
||||
{ "account_lines", &RPCParser::parseAccountItems, 1, 2 },
|
||||
{ "account_offers", &RPCParser::parseAccountItems, 1, 2 },
|
||||
{ "account_tx", &RPCParser::parseAccountTransactions, 2, 4 },
|
||||
{ "account_tx", &RPCParser::parseAccountTransactions, 1, 8 },
|
||||
{ "book_offers", &RPCParser::parseBookOffers, 2, 7 },
|
||||
{ "connect", &RPCParser::parseConnect, 1, 2 },
|
||||
{ "consensus_info", &RPCParser::parseAsIs, 0, 0 },
|
||||
@@ -660,7 +662,7 @@ Json::Value RPCParser::parseCommand(std::string strMethod, Json::Value jvParams)
|
||||
{ "log_level", &RPCParser::parseLogLevel, 0, 2 },
|
||||
{ "logrotate", &RPCParser::parseAsIs, 0, 0 },
|
||||
// { "nickname_info", &RPCParser::parseNicknameInfo, 1, 1 },
|
||||
{ "owner_info", &RPCParser::parseOwnerInfo, 1, 2 },
|
||||
{ "owner_info", &RPCParser::parseAccountItems, 1, 2 },
|
||||
{ "peers", &RPCParser::parseAsIs, 0, 0 },
|
||||
{ "ping", &RPCParser::parseAsIs, 0, 0 },
|
||||
// { "profile", &RPCParser::parseProfile, 1, 9 },
|
||||
|
||||
@@ -10,7 +10,6 @@ class RPCParser
|
||||
protected:
|
||||
typedef Json::Value (RPCParser::*parseFuncPtr)(const Json::Value &jvParams);
|
||||
|
||||
Json::Value parseAccountInfo(const Json::Value& jvParams);
|
||||
Json::Value parseAccountItems(const Json::Value& jvParams);
|
||||
Json::Value parseAccountTransactions(const Json::Value& jvParams);
|
||||
Json::Value parseAsIs(const Json::Value& jvParams);
|
||||
|
||||
@@ -306,7 +306,7 @@ void Config::load()
|
||||
smtTmp = sectionEntries(secConfig, SECTION_RPC_STARTUP);
|
||||
if (smtTmp)
|
||||
{
|
||||
Json::Value jvArray(Json::arrayValue);
|
||||
RPC_STARTUP = Json::arrayValue;
|
||||
|
||||
BOOST_FOREACH(const std::string& strJson, *smtTmp)
|
||||
{
|
||||
@@ -316,10 +316,8 @@ void Config::load()
|
||||
if (!jrReader.parse(strJson, jvCommand))
|
||||
throw std::runtime_error(boost::str(boost::format("Couldn't parse [" SECTION_RPC_STARTUP "] command: %s") % strJson));
|
||||
|
||||
jvArray.append(jvCommand);
|
||||
RPC_STARTUP.append(jvCommand);
|
||||
}
|
||||
|
||||
RPC_STARTUP = jvArray;
|
||||
}
|
||||
|
||||
if (sectionSingleB(secConfig, SECTION_DATABASE_PATH, DATABASE_PATH))
|
||||
@@ -498,7 +496,7 @@ int Config::getSize(SizedItemName item)
|
||||
{ siLineCacheSize, { 8192, 32768, 131072, 1048576, 0 } },
|
||||
{ siLineCacheAge, { 500, 600, 1800, 3600, 7200 } },
|
||||
{ siHashNodeDBCache, { 24, 48, 64, 128, 256 } },
|
||||
{ siTxnDBCache, { 4, 8, 32, 64, 128 } },
|
||||
{ siTxnDBCache, { 4, 12, 48, 96, 192 } },
|
||||
{ siLgrDBCache, { 4, 8, 32, 64, 128 } }
|
||||
};
|
||||
|
||||
|
||||
@@ -19,6 +19,9 @@ const char *TxnDBInit[] = {
|
||||
RawTxn BLOB, \
|
||||
TxnMeta BLOB \
|
||||
);",
|
||||
"CREATE INDEX TxLgrIndex ON \
|
||||
Transactions(LedgerSeq);",
|
||||
|
||||
"CREATE TABLE AccountTransactions ( \
|
||||
TransID CHARACTER(64), \
|
||||
Account CHARACTER(64), \
|
||||
|
||||
@@ -183,8 +183,8 @@ HashedObject::pointer HashedObjectStore::retrieve(const uint256& hash)
|
||||
|
||||
#ifndef NO_SQLITE3_PREPARE
|
||||
{
|
||||
LoadEvent::autoptr event(theApp->getJobQueue().getLoadEventAP(jtDISK, "HOS::retrieve"));
|
||||
ScopedLock sl(theApp->getHashNodeDB()->getDBLock());
|
||||
LoadEvent::autoptr event(theApp->getJobQueue().getLoadEventAP(jtDISK, "HOS::retrieve"));
|
||||
static SqliteStatement pSt(theApp->getHashNodeDB()->getDB()->getSqliteDB(),
|
||||
"SELECT ObjType,LedgerIndex,Object FROM CommittedObjects WHERE Hash = ?;");
|
||||
|
||||
|
||||
@@ -50,6 +50,11 @@ public:
|
||||
sMultiThreaded = true;
|
||||
}
|
||||
|
||||
static void shutdown()
|
||||
{
|
||||
sMultiThreaded = false;
|
||||
}
|
||||
|
||||
static bool isMultiThread()
|
||||
{
|
||||
return sMultiThreaded;
|
||||
|
||||
@@ -6,10 +6,12 @@
|
||||
|
||||
#include "Log.h"
|
||||
#include "Config.h"
|
||||
#include "Application.h"
|
||||
|
||||
SETUP_LOG();
|
||||
|
||||
JobQueue::JobQueue() : mLastJob(0), mThreadCount(0), mShuttingDown(false)
|
||||
JobQueue::JobQueue(boost::asio::io_service& svc)
|
||||
: mLastJob(0), mThreadCount(0), mShuttingDown(false), mIOThreadCount(0), mMaxIOThreadCount(1), mIOService(svc)
|
||||
{
|
||||
mJobLoads[jtPUBOLDLEDGER].setTargetLatency(10000, 15000);
|
||||
mJobLoads[jtVALIDATION_ut].setTargetLatency(2000, 5000);
|
||||
@@ -240,6 +242,8 @@ void JobQueue::setThreadCount(int c)
|
||||
|
||||
boost::mutex::scoped_lock sl(mJobLock);
|
||||
|
||||
mMaxIOThreadCount = 1 + (c / 3);
|
||||
|
||||
while (mJobCounts[jtDEATH].first != 0)
|
||||
mJobCond.wait(sl);
|
||||
|
||||
@@ -261,6 +265,26 @@ void JobQueue::setThreadCount(int c)
|
||||
mJobCond.notify_one(); // in case we sucked up someone else's signal
|
||||
}
|
||||
|
||||
void JobQueue::IOThread(boost::mutex::scoped_lock& sl)
|
||||
{ // call with a lock
|
||||
++mIOThreadCount;
|
||||
sl.unlock();
|
||||
NameThread("IO+");
|
||||
try
|
||||
{
|
||||
do
|
||||
NameThread("IO+");
|
||||
while ((mIOService.poll_one() == 1) && !theApp->isShutdown());
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
cLog(lsWARNING) << "Exception in IOThread";
|
||||
}
|
||||
NameThread("waiting");
|
||||
sl.lock();
|
||||
--mIOThreadCount;
|
||||
}
|
||||
|
||||
void JobQueue::threadEntry()
|
||||
{ // do jobs until asked to stop
|
||||
boost::mutex::scoped_lock sl(mJobLock);
|
||||
@@ -268,7 +292,12 @@ void JobQueue::threadEntry()
|
||||
{
|
||||
NameThread("waiting");
|
||||
while (mJobSet.empty() && !mShuttingDown)
|
||||
mJobCond.wait(sl);
|
||||
{
|
||||
if ((mIOThreadCount < mMaxIOThreadCount) && !theApp->isShutdown())
|
||||
IOThread(sl);
|
||||
else
|
||||
mJobCond.wait(sl);
|
||||
}
|
||||
|
||||
if (mShuttingDown)
|
||||
break;
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/condition_variable.hpp>
|
||||
#include <boost/make_shared.hpp>
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/ref.hpp>
|
||||
|
||||
#include "../json/value.h"
|
||||
@@ -93,14 +94,19 @@ protected:
|
||||
int mThreadCount;
|
||||
bool mShuttingDown;
|
||||
|
||||
int mIOThreadCount;
|
||||
int mMaxIOThreadCount;
|
||||
boost::asio::io_service& mIOService;
|
||||
|
||||
std::map<JobType, std::pair<int, int > > mJobCounts;
|
||||
|
||||
|
||||
void threadEntry(void);
|
||||
void threadEntry();
|
||||
void IOThread(boost::mutex::scoped_lock&);
|
||||
|
||||
public:
|
||||
|
||||
JobQueue();
|
||||
JobQueue(boost::asio::io_service&);
|
||||
|
||||
void addJob(JobType type, const std::string& name, const FUNCTION_TYPE<void(Job&)>& job);
|
||||
|
||||
|
||||
@@ -13,9 +13,9 @@ SETUP_LOG();
|
||||
DECLARE_INSTANCE(LedgerAcquire);
|
||||
|
||||
#define LA_DEBUG
|
||||
#define LEDGER_ACQUIRE_TIMEOUT 1000 // millisecond for each ledger timeout
|
||||
#define LEDGER_ACQUIRE_TIMEOUT 2000 // millisecond for each ledger timeout
|
||||
#define LEDGER_TIMEOUT_COUNT 10 // how many timeouts before we giveup
|
||||
#define LEDGER_TIMEOUT_AGGRESSIVE 4 // how many timeouts before we get aggressive
|
||||
#define LEDGER_TIMEOUT_AGGRESSIVE 6 // how many timeouts before we get aggressive
|
||||
#define TRUST_NETWORK
|
||||
|
||||
PeerSet::PeerSet(const uint256& hash, int interval) : mHash(hash), mTimerInterval(interval), mTimeouts(0),
|
||||
@@ -98,7 +98,7 @@ bool PeerSet::isActive()
|
||||
|
||||
LedgerAcquire::LedgerAcquire(const uint256& hash) : PeerSet(hash, LEDGER_ACQUIRE_TIMEOUT),
|
||||
mHaveBase(false), mHaveState(false), mHaveTransactions(false), mAborted(false), mSignaled(false), mAccept(false),
|
||||
mByHash(true)
|
||||
mByHash(true), mWaitCount(0)
|
||||
{
|
||||
#ifdef LA_DEBUG
|
||||
cLog(lsTRACE) << "Acquiring ledger " << mHash;
|
||||
@@ -191,6 +191,9 @@ bool LedgerAcquire::tryLocal()
|
||||
|
||||
void LedgerAcquire::onTimer(bool progress)
|
||||
{
|
||||
mRecentTXNodes.clear();
|
||||
mRecentASNodes.clear();
|
||||
|
||||
if (getTimeouts() > LEDGER_TIMEOUT_COUNT)
|
||||
{
|
||||
cLog(lsWARNING) << "Too many timeouts for ledger " << mHash;
|
||||
@@ -199,21 +202,31 @@ void LedgerAcquire::onTimer(bool progress)
|
||||
return;
|
||||
}
|
||||
|
||||
mRecentTXNodes.clear();
|
||||
mRecentASNodes.clear();
|
||||
|
||||
if (!progress)
|
||||
{
|
||||
mAggressive = true;
|
||||
mByHash = true;
|
||||
cLog(lsDEBUG) << "No progress for ledger " << mHash;
|
||||
if (!getPeerCount())
|
||||
int pc = getPeerCount();
|
||||
cLog(lsDEBUG) << "No progress(" << pc << ") for ledger " << pc << mHash;
|
||||
if (pc == 0)
|
||||
addPeers();
|
||||
else
|
||||
trigger(Peer::pointer());
|
||||
}
|
||||
}
|
||||
|
||||
void LedgerAcquire::awaitData()
|
||||
{
|
||||
boost::recursive_mutex::scoped_lock sl(mLock);
|
||||
++mWaitCount;
|
||||
}
|
||||
|
||||
void LedgerAcquire::noAwaitData()
|
||||
{
|
||||
boost::recursive_mutex::scoped_lock sl(mLock);
|
||||
if (mWaitCount > 0 ) --mWaitCount;
|
||||
}
|
||||
|
||||
void LedgerAcquire::addPeers()
|
||||
{
|
||||
std::vector<Peer::pointer> peerList = theApp->getConnectionPool().getPeerVector();
|
||||
@@ -295,8 +308,16 @@ void LedgerAcquire::trigger(Peer::ref peer)
|
||||
boost::recursive_mutex::scoped_lock sl(mLock);
|
||||
if (mAborted || mComplete || mFailed)
|
||||
{
|
||||
cLog(lsTRACE) << "Trigger on ledger:" <<
|
||||
(mAborted ? " aborted": "") << (mComplete ? " completed": "") << (mFailed ? " failed" : "");
|
||||
cLog(lsDEBUG) << "Trigger on ledger:" <<
|
||||
(mAborted ? " aborted": "") << (mComplete ? " completed": "") << (mFailed ? " failed" : "") <<
|
||||
" wc=" << mWaitCount;
|
||||
return;
|
||||
}
|
||||
|
||||
if ((mWaitCount > 0) && peer)
|
||||
{
|
||||
mRecentPeers.push_back(peer->getPeerId());
|
||||
cLog(lsTRACE) << "Deferring peer";
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -484,6 +505,8 @@ void LedgerAcquire::trigger(Peer::ref peer)
|
||||
}
|
||||
}
|
||||
|
||||
mRecentPeers.clear();
|
||||
|
||||
if (mComplete || mFailed)
|
||||
{
|
||||
cLog(lsDEBUG) << "Done:" << (mComplete ? " complete" : "") << (mFailed ? " failed " : " ")
|
||||
@@ -786,13 +809,13 @@ std::vector<LedgerAcquire::neededHash_t> LedgerAcquire::getNeededHashes()
|
||||
}
|
||||
if (!mHaveState)
|
||||
{
|
||||
std::vector<uint256> v = mLedger->getNeededAccountStateHashes(16);
|
||||
std::vector<uint256> v = mLedger->getNeededAccountStateHashes(4);
|
||||
BOOST_FOREACH(const uint256& h, v)
|
||||
ret.push_back(std::make_pair(ripple::TMGetObjectByHash::otSTATE_NODE, h));
|
||||
}
|
||||
if (!mHaveTransactions)
|
||||
{
|
||||
std::vector<uint256> v = mLedger->getNeededAccountStateHashes(16);
|
||||
std::vector<uint256> v = mLedger->getNeededAccountStateHashes(4);
|
||||
BOOST_FOREACH(const uint256& h, v)
|
||||
ret.push_back(std::make_pair(ripple::TMGetObjectByHash::otTRANSACTION_NODE, h));
|
||||
}
|
||||
@@ -846,21 +869,21 @@ void LedgerAcquireMaster::dropLedger(const uint256& hash)
|
||||
mLedgers.erase(hash);
|
||||
}
|
||||
|
||||
void LedgerAcquireMaster::gotLedgerData(Job&, boost::shared_ptr<ripple::TMLedgerData> packet_ptr,
|
||||
boost::weak_ptr<Peer> wPeer)
|
||||
bool LedgerAcquireMaster::awaitLedgerData(const uint256& ledgerHash)
|
||||
{
|
||||
LedgerAcquire::pointer ledger = find(ledgerHash);
|
||||
if (!ledger)
|
||||
return false;
|
||||
ledger->awaitData();
|
||||
return true;
|
||||
}
|
||||
|
||||
void LedgerAcquireMaster::gotLedgerData(Job&, uint256 hash,
|
||||
boost::shared_ptr<ripple::TMLedgerData> packet_ptr, boost::weak_ptr<Peer> wPeer)
|
||||
{
|
||||
ripple::TMLedgerData& packet = *packet_ptr;
|
||||
Peer::pointer peer = wPeer.lock();
|
||||
if (!peer)
|
||||
return;
|
||||
|
||||
uint256 hash;
|
||||
if (packet.ledgerhash().size() != 32)
|
||||
{
|
||||
peer->punishPeer(LT_InvalidRequest);
|
||||
return;
|
||||
}
|
||||
memcpy(hash.begin(), packet.ledgerhash().data(), 32);
|
||||
cLog(lsTRACE) << "Got data (" << packet.nodes().size() << ") for acquiring ledger: " << hash;
|
||||
|
||||
LedgerAcquire::pointer ledger = find(hash);
|
||||
@@ -870,6 +893,10 @@ void LedgerAcquireMaster::gotLedgerData(Job&, boost::shared_ptr<ripple::TMLedger
|
||||
peer->punishPeer(LT_InvalidRequest);
|
||||
return;
|
||||
}
|
||||
ledger->noAwaitData();
|
||||
|
||||
if (!peer)
|
||||
return;
|
||||
|
||||
if (packet.type() == ripple::liBASE)
|
||||
{
|
||||
|
||||
@@ -87,11 +87,14 @@ public:
|
||||
protected:
|
||||
Ledger::pointer mLedger;
|
||||
bool mHaveBase, mHaveState, mHaveTransactions, mAborted, mSignaled, mAccept, mByHash;
|
||||
int mWaitCount;
|
||||
|
||||
std::set<SHAMapNode> mRecentTXNodes;
|
||||
std::set<SHAMapNode> mRecentASNodes;
|
||||
|
||||
std::vector< FUNCTION_TYPE<void (LedgerAcquire::pointer)> > mOnComplete;
|
||||
std::vector<uint64> mRecentPeers;
|
||||
|
||||
std::vector< FUNCTION_TYPE<void (LedgerAcquire::pointer)> > mOnComplete;
|
||||
|
||||
void done();
|
||||
void onTimer(bool progress);
|
||||
@@ -124,6 +127,8 @@ public:
|
||||
void trigger(Peer::ref);
|
||||
bool tryLocal();
|
||||
void addPeers();
|
||||
void awaitData();
|
||||
void noAwaitData();
|
||||
|
||||
typedef std::pair<ripple::TMGetObjectByHash::ObjectType, uint256> neededHash_t;
|
||||
std::vector<neededHash_t> getNeededHashes();
|
||||
@@ -148,7 +153,9 @@ public:
|
||||
LedgerAcquire::pointer find(const uint256& hash);
|
||||
bool hasLedger(const uint256& ledgerHash);
|
||||
void dropLedger(const uint256& ledgerHash);
|
||||
void gotLedgerData(Job&, boost::shared_ptr<ripple::TMLedgerData> packet, boost::weak_ptr<Peer> peer);
|
||||
|
||||
bool awaitLedgerData(const uint256& ledgerHash);
|
||||
void gotLedgerData(Job&, uint256 hash, boost::shared_ptr<ripple::TMLedgerData> packet, boost::weak_ptr<Peer> peer);
|
||||
|
||||
int getFetchCount(int& timeoutCount);
|
||||
void logFailure(const uint256& h) { mRecentFailures.add(h); }
|
||||
|
||||
@@ -230,6 +230,15 @@ void LedgerEntrySet::entryDelete(SLE::ref sle)
|
||||
}
|
||||
}
|
||||
|
||||
bool LedgerEntrySet::hasChanges()
|
||||
{
|
||||
typedef std::map<uint256, LedgerEntrySetEntry>::value_type u256_LES_pair;
|
||||
BOOST_FOREACH(u256_LES_pair& it, mEntries)
|
||||
if (it.second.mAction != taaCACHED)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool LedgerEntrySet::intersect(const LedgerEntrySet& lesLeft, const LedgerEntrySet& lesRight)
|
||||
{
|
||||
return true; // XXX Needs implementation
|
||||
|
||||
@@ -95,6 +95,7 @@ public:
|
||||
void entryCreate(SLE::ref); // This entry will be created
|
||||
void entryDelete(SLE::ref); // This entry will be deleted
|
||||
void entryModify(SLE::ref); // This entry will be modified
|
||||
bool hasChanges(); // True if LES has any changes
|
||||
|
||||
// higher-level ledger functions
|
||||
SLE::pointer entryCreate(LedgerEntryType letType, const uint256& uIndex);
|
||||
|
||||
@@ -141,6 +141,22 @@ bool LedgerMaster::haveLedger(uint32 seq)
|
||||
return mCompleteLedgers.hasValue(seq);
|
||||
}
|
||||
|
||||
bool LedgerMaster::getValidatedRange(uint32& minVal, uint32& maxVal)
|
||||
{
|
||||
boost::recursive_mutex::scoped_lock sl(mLock);
|
||||
if (!mValidLedger)
|
||||
return false;
|
||||
maxVal = mValidLedger->getLedgerSeq();
|
||||
if (maxVal == 0)
|
||||
return false;
|
||||
minVal = mCompleteLedgers.prevMissing(maxVal);
|
||||
if (minVal == RangeSet::RangeSetAbsent)
|
||||
minVal = 0;
|
||||
else
|
||||
++minVal;
|
||||
return true;
|
||||
}
|
||||
|
||||
void LedgerMaster::asyncAccept(Ledger::pointer ledger)
|
||||
{
|
||||
uint32 seq = ledger->getLedgerSeq();
|
||||
@@ -232,7 +248,7 @@ bool LedgerMaster::acquireMissingLedger(Ledger::ref origLedger, const uint256& l
|
||||
int timeoutCount;
|
||||
int fetchCount = theApp->getMasterLedgerAcquire().getFetchCount(timeoutCount);
|
||||
|
||||
if (fetchCount < fetchMax)
|
||||
if ((fetchCount < fetchMax) && theApp->getOPs().isFull())
|
||||
{
|
||||
if (timeoutCount > 2)
|
||||
{
|
||||
@@ -289,7 +305,7 @@ bool LedgerMaster::shouldAcquire(uint32 currentLedger, uint32 ledgerHistory, uin
|
||||
|
||||
void LedgerMaster::resumeAcquiring()
|
||||
{
|
||||
if (theApp->getOPs().isNeedNetworkLedger())
|
||||
if (!theApp->getOPs().isFull())
|
||||
return;
|
||||
|
||||
boost::recursive_mutex::scoped_lock ml(mLock);
|
||||
|
||||
@@ -143,6 +143,7 @@ public:
|
||||
|
||||
bool haveLedgerRange(uint32 from, uint32 to);
|
||||
bool haveLedger(uint32 seq);
|
||||
bool getValidatedRange(uint32& minVal, uint32& maxVal);
|
||||
|
||||
void resumeAcquiring();
|
||||
|
||||
|
||||
@@ -564,7 +564,7 @@ Json::Value NetworkOPs::getOwnerInfo(Ledger::pointer lpLedger, const RippleAddre
|
||||
//
|
||||
|
||||
void NetworkOPs::setStateTimer()
|
||||
{ // set timer early if ledger is closing
|
||||
{
|
||||
mNetTimer.expires_from_now(boost::posix_time::milliseconds(LEDGER_GRANULARITY));
|
||||
mNetTimer.async_wait(boost::bind(&NetworkOPs::checkState, this, boost::asio::placeholders::error));
|
||||
}
|
||||
@@ -594,36 +594,41 @@ void NetworkOPs::checkState(const boost::system::error_code& result)
|
||||
{ // Network state machine
|
||||
|
||||
if ((result == boost::asio::error::operation_aborted) || theConfig.RUN_STANDALONE)
|
||||
{
|
||||
cLog(lsFATAL) << "Network state timer error: " << result;
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
ScopedLock(theApp->getMasterLock());
|
||||
|
||||
std::vector<Peer::pointer> peerList = theApp->getConnectionPool().getPeerVector();
|
||||
|
||||
// do we have sufficient peers? If not, we are disconnected.
|
||||
if (peerList.size() < theConfig.NETWORK_QUORUM)
|
||||
{
|
||||
if (mMode != omDISCONNECTED)
|
||||
{
|
||||
setMode(omDISCONNECTED);
|
||||
cLog(lsWARNING) << "Node count (" << peerList.size() <<
|
||||
") has fallen below quorum (" << theConfig.NETWORK_QUORUM << ").";
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (mMode == omDISCONNECTED)
|
||||
{
|
||||
setMode(omCONNECTED);
|
||||
cLog(lsINFO) << "Node count (" << peerList.size() << ") is sufficient.";
|
||||
}
|
||||
|
||||
if (!mConsensus)
|
||||
tryStartConsensus();
|
||||
|
||||
if (mConsensus)
|
||||
mConsensus->timerEntry();
|
||||
}
|
||||
|
||||
setStateTimer();
|
||||
|
||||
ScopedLock(theApp->getMasterLock());
|
||||
|
||||
std::vector<Peer::pointer> peerList = theApp->getConnectionPool().getPeerVector();
|
||||
|
||||
// do we have sufficient peers? If not, we are disconnected.
|
||||
if (peerList.size() < theConfig.NETWORK_QUORUM)
|
||||
{
|
||||
if (mMode != omDISCONNECTED)
|
||||
{
|
||||
setMode(omDISCONNECTED);
|
||||
cLog(lsWARNING) << "Node count (" << peerList.size() <<
|
||||
") has fallen below quorum (" << theConfig.NETWORK_QUORUM << ").";
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (mMode == omDISCONNECTED)
|
||||
{
|
||||
setMode(omCONNECTED);
|
||||
cLog(lsINFO) << "Node count (" << peerList.size() << ") is sufficient.";
|
||||
}
|
||||
|
||||
if (!mConsensus)
|
||||
tryStartConsensus();
|
||||
|
||||
if (mConsensus)
|
||||
mConsensus->timerEntry();
|
||||
}
|
||||
|
||||
void NetworkOPs::tryStartConsensus()
|
||||
@@ -1059,17 +1064,56 @@ void NetworkOPs::setMode(OperatingMode om)
|
||||
}
|
||||
|
||||
|
||||
std::string
|
||||
NetworkOPs::transactionsSQL(std::string selection, const RippleAddress& account,
|
||||
int32 minLedger, int32 maxLedger, bool descending, uint32 offset, int limit,
|
||||
bool binary, bool count, bool bAdmin)
|
||||
{
|
||||
uint32 NONBINARY_PAGE_LENGTH = 200;
|
||||
uint32 BINARY_PAGE_LENGTH = 500;
|
||||
|
||||
uint32 numberOfResults;
|
||||
if (count)
|
||||
numberOfResults = 1000000000;
|
||||
else if (limit < 0)
|
||||
numberOfResults = binary ? BINARY_PAGE_LENGTH : NONBINARY_PAGE_LENGTH;
|
||||
else if (!bAdmin)
|
||||
numberOfResults = std::min(binary ? BINARY_PAGE_LENGTH : NONBINARY_PAGE_LENGTH, static_cast<uint32>(limit));
|
||||
else
|
||||
numberOfResults = limit;
|
||||
|
||||
std::string maxClause = "";
|
||||
std::string minClause = "";
|
||||
if (maxLedger != -1)
|
||||
maxClause = boost::str(boost::format("AND AccountTransactions.LedgerSeq <= '%u'") % maxLedger);
|
||||
if (minLedger != -1)
|
||||
minClause = boost::str(boost::format("AND AccountTransactions.LedgerSeq >= '%u'") % minLedger);
|
||||
|
||||
std::string sql =
|
||||
boost::str(boost::format("SELECT %s FROM "
|
||||
"AccountTransactions INNER JOIN Transactions ON Transactions.TransID = AccountTransactions.TransID "
|
||||
"WHERE Account = '%s' %s %s "
|
||||
"ORDER BY AccountTransactions.LedgerSeq %s, AccountTransactions.TransID %s LIMIT %u, %u;")
|
||||
% selection
|
||||
% account.humanAccountID()
|
||||
% maxClause
|
||||
% minClause
|
||||
% (descending ? "DESC" : "ASC")
|
||||
% (descending ? "DESC" : "ASC")
|
||||
% boost::lexical_cast<std::string>(offset)
|
||||
% boost::lexical_cast<std::string>(numberOfResults)
|
||||
);
|
||||
cLog(lsTRACE) << "txSQL query: " << sql;
|
||||
return sql;
|
||||
}
|
||||
|
||||
std::vector< std::pair<Transaction::pointer, TransactionMetaSet::pointer> >
|
||||
NetworkOPs::getAccountTxs(const RippleAddress& account, uint32 minLedger, uint32 maxLedger)
|
||||
NetworkOPs::getAccountTxs(const RippleAddress& account, int32 minLedger, int32 maxLedger, bool descending, uint32 offset, int limit, bool bAdmin)
|
||||
{ // can be called with no locks
|
||||
std::vector< std::pair<Transaction::pointer, TransactionMetaSet::pointer> > ret;
|
||||
|
||||
std::string sql =
|
||||
str(boost::format("SELECT AccountTransactions.LedgerSeq,Status,RawTxn,TxnMeta FROM "
|
||||
"AccountTransactions INNER JOIN Transactions ON Transactions.TransID = AccountTransactions.TransID "
|
||||
"WHERE Account = '%s' AND AccountTransactions.LedgerSeq <= '%u' AND AccountTransactions.LedgerSeq >= '%u' "
|
||||
"ORDER BY AccountTransactions.LedgerSeq,AccountTransactions.TransID DESC LIMIT 200;")
|
||||
% account.humanAccountID() % maxLedger % minLedger);
|
||||
std::string sql = NetworkOPs::transactionsSQL("AccountTransactions.LedgerSeq,Status,RawTxn,TxnMeta", account,
|
||||
minLedger, maxLedger, descending, offset, limit, false, false, bAdmin);
|
||||
|
||||
{
|
||||
Database* db = theApp->getTxnDB()->getDB();
|
||||
@@ -1098,15 +1142,12 @@ std::vector< std::pair<Transaction::pointer, TransactionMetaSet::pointer> >
|
||||
}
|
||||
|
||||
std::vector<NetworkOPs::txnMetaLedgerType> NetworkOPs::getAccountTxsB(
|
||||
const RippleAddress& account, uint32 minLedger, uint32 maxLedger)
|
||||
const RippleAddress& account, int32 minLedger, int32 maxLedger, bool descending, uint32 offset, int limit, bool bAdmin)
|
||||
{ // can be called with no locks
|
||||
std::vector< txnMetaLedgerType> ret;
|
||||
|
||||
std::string sql = str(boost::format("SELECT AccountTransactions.LedgerSeq,Status,RawTxn,TxnMeta FROM "
|
||||
"AccountTransactions INNER JOIN Transactions ON Transactions.TransID = AccountTransactions.TransID "
|
||||
"WHERE Account = '%s' AND AccountTransactions.LedgerSeq <= '%u' AND AccountTransactions.LedgerSeq >= '%u' "
|
||||
"ORDER BY AccountTransactions.LedgerSeq,AccountTransactions.TransID DESC LIMIT 500;")
|
||||
% account.humanAccountID() % maxLedger % minLedger);
|
||||
std::string sql = NetworkOPs::transactionsSQL("AccountTransactions.LedgerSeq,Status,RawTxn,TxnMeta", account,
|
||||
minLedger, maxLedger, descending, offset, limit, true/*binary*/, false, bAdmin);
|
||||
|
||||
{
|
||||
Database* db = theApp->getTxnDB()->getDB();
|
||||
@@ -1144,6 +1185,26 @@ std::vector<NetworkOPs::txnMetaLedgerType> NetworkOPs::getAccountTxsB(
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
uint32
|
||||
NetworkOPs::countAccountTxs(const RippleAddress& account, int32 minLedger, int32 maxLedger)
|
||||
{ // can be called with no locks
|
||||
uint32 ret = 0;
|
||||
std::string sql = NetworkOPs::transactionsSQL("COUNT(*) AS 'TransactionCount'", account,
|
||||
minLedger, maxLedger, false, 0, -1, true, true, true);
|
||||
|
||||
Database* db = theApp->getTxnDB()->getDB();
|
||||
ScopedLock sl(theApp->getTxnDB()->getDBLock());
|
||||
SQL_FOREACH(db, sql)
|
||||
{
|
||||
ret = db->getInt("TransactionCount");
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
std::vector<RippleAddress>
|
||||
NetworkOPs::getLedgerAffectedAccounts(uint32 ledgerSeq)
|
||||
{
|
||||
|
||||
@@ -175,6 +175,7 @@ public:
|
||||
bool isValidated(uint32 seq);
|
||||
bool isValidated(uint32 seq, const uint256& hash);
|
||||
bool isValidated(Ledger::ref l) { return isValidated(l->getLedgerSeq(), l->getHash()); }
|
||||
bool getValidatedRange(uint32& minVal, uint32& maxVal) { return mLedgerMaster->getValidatedRange(minVal, maxVal); }
|
||||
|
||||
SerializedValidation::ref getLastValidation() { return mLastValidation; }
|
||||
void setLastValidation(SerializedValidation::ref v) { mLastValidation = v; }
|
||||
@@ -272,6 +273,7 @@ public:
|
||||
void needNetworkLedger() { mNeedNetworkLedger = true; }
|
||||
void clearNeedNetworkLedger() { mNeedNetworkLedger = false; }
|
||||
bool isNeedNetworkLedger() { return mNeedNetworkLedger; }
|
||||
bool isFull() { return !mNeedNetworkLedger && (mMode == omFULL); }
|
||||
void setProposing(bool p, bool v) { mProposing = p; mValidating = v; }
|
||||
bool isProposing() { return mProposing; }
|
||||
bool isValidating() { return mValidating; }
|
||||
@@ -292,17 +294,23 @@ public:
|
||||
bool addWantedHash(const uint256& h);
|
||||
bool isWantedHash(const uint256& h, bool remove);
|
||||
|
||||
//Helper function to generate SQL query to get transactions
|
||||
std::string transactionsSQL(std::string selection, const RippleAddress& account,
|
||||
int32 minLedger, int32 maxLedger, bool descending, uint32 offset, int limit,
|
||||
bool binary, bool count, bool bAdmin);
|
||||
|
||||
|
||||
// client information retrieval functions
|
||||
std::vector< std::pair<Transaction::pointer, TransactionMetaSet::pointer> >
|
||||
getAccountTxs(const RippleAddress& account, uint32 minLedger, uint32 maxLedger);
|
||||
getAccountTxs(const RippleAddress& account, int32 minLedger, int32 maxLedger, bool descending, uint32 offset, int limit, bool bAdmin);
|
||||
|
||||
typedef boost::tuple<std::string, std::string, uint32> txnMetaLedgerType;
|
||||
std::vector<txnMetaLedgerType>
|
||||
getAccountTxsB(const RippleAddress& account, uint32 minL, uint32 maxL);
|
||||
getAccountTxsB(const RippleAddress& account, int32 minLedger, int32 maxLedger, bool descending, uint32 offset, int limit, bool bAdmin);
|
||||
|
||||
std::vector<RippleAddress> getLedgerAffectedAccounts(uint32 ledgerSeq);
|
||||
std::vector<SerializedTransaction> getLedgerTransactions(uint32 ledgerSeq);
|
||||
|
||||
uint32 countAccountTxs(const RippleAddress& account, int32 minLedger, int32 maxLedger);
|
||||
//
|
||||
// Monitoring: publisher side
|
||||
//
|
||||
|
||||
@@ -119,6 +119,10 @@ bool Pathfinder::bDefaultPath(const STPath& spPath)
|
||||
bool bDefault;
|
||||
LedgerEntrySet lesActive(mLedger, tapNONE);
|
||||
|
||||
cLog(lsTRACE) << boost::str(boost::format("bDefaultPath> mSrcAmount=%s mDstAmount=%s")
|
||||
% mSrcAmount.getFullText()
|
||||
% mDstAmount.getFullText());
|
||||
|
||||
// Expand the current path.
|
||||
pspCurrent->setExpanded(lesActive, spPath, mDstAccountID, mSrcAccountID);
|
||||
|
||||
@@ -126,8 +130,8 @@ bool Pathfinder::bDefaultPath(const STPath& spPath)
|
||||
// When path is a default (implied). Don't need to add it to return set.
|
||||
bDefault = pspCurrent->vpnNodes == mPsDefault->vpnNodes;
|
||||
|
||||
cLog(lsTRACE) << "findPaths: expanded path: " << pspCurrent->getJson();
|
||||
cLog(lsTRACE) << "findPaths: default path: indirect: " << spPath.getJson(0);
|
||||
cLog(lsTRACE) << "bDefaultPath: expanded path: " << pspCurrent->getJson();
|
||||
cLog(lsTRACE) << "bDefaultPath: default path: indirect: " << spPath.getJson(0);
|
||||
|
||||
return bDefault;
|
||||
}
|
||||
@@ -162,6 +166,10 @@ Pathfinder::Pathfinder(Ledger::ref ledger,
|
||||
|
||||
LedgerEntrySet lesActive(mLedger, tapNONE);
|
||||
|
||||
cLog(lsTRACE) << boost::str(boost::format("Pathfinder> mSrcAmount=%s mDstAmount=%s")
|
||||
% mSrcAmount.getFullText()
|
||||
% mDstAmount.getFullText());
|
||||
|
||||
psDefault->setExpanded(lesActive, STPath(), mDstAccountID, mSrcAccountID);
|
||||
|
||||
if (tesSUCCESS == psDefault->terStatus)
|
||||
@@ -296,6 +304,12 @@ bool Pathfinder::findPaths(const unsigned int iMaxSteps, const unsigned int iMax
|
||||
|
||||
if (sLog(lsTRACE))
|
||||
{
|
||||
cLog(lsTRACE) << boost::str(boost::format("findPaths: spe: %s/%s: %s amt: %s")
|
||||
% RippleAddress::createHumanAccountID(speEnd.mAccountID)
|
||||
% RippleAddress::createHumanAccountID(speEnd.mIssuerID)
|
||||
% RippleAddress::createHumanAccountID(mDstAccountID)
|
||||
% RippleAddress::createHumanAccountID(mDstAmount.getIssuer()));
|
||||
|
||||
cLog(lsTRACE) << "findPaths: finish? account: " << (speEnd.mAccountID == mDstAccountID);
|
||||
cLog(lsTRACE) << "findPaths: finish? currency: " << (speEnd.mCurrencyID == mDstAmount.getCurrency());
|
||||
cLog(lsTRACE) << "findPaths: finish? issuer: "
|
||||
@@ -408,7 +422,7 @@ bool Pathfinder::findPaths(const unsigned int iMaxSteps, const unsigned int iMax
|
||||
SLE::pointer sleEnd = lesActive.entryCache(ltACCOUNT_ROOT, Ledger::getAccountRootIndex(speEnd.mAccountID));
|
||||
|
||||
tLog(!sleEnd, lsDEBUG)
|
||||
<< boost::str(boost::format("findPaths: order book: %s/%s : ")
|
||||
<< boost::str(boost::format("findPaths: tail: %s/%s : ")
|
||||
% RippleAddress::createHumanAccountID(speEnd.mAccountID)
|
||||
% RippleAddress::createHumanAccountID(speEnd.mIssuerID));
|
||||
|
||||
@@ -445,11 +459,14 @@ bool Pathfinder::findPaths(const unsigned int iMaxSteps, const unsigned int iMax
|
||||
{
|
||||
// Path has no credit left. Ignore it.
|
||||
cLog(lsTRACE) <<
|
||||
boost::str(boost::format("findPaths: No credit: %s/%s -> %s/%s")
|
||||
boost::str(boost::format("findPaths: No credit: %s/%s -> %s/%s balance=%s limit=%s")
|
||||
% RippleAddress::createHumanAccountID(speEnd.mAccountID)
|
||||
% STAmount::createHumanCurrency(speEnd.mCurrencyID)
|
||||
% RippleAddress::createHumanAccountID(uPeerID)
|
||||
% STAmount::createHumanCurrency(speEnd.mCurrencyID));
|
||||
% STAmount::createHumanCurrency(speEnd.mCurrencyID)
|
||||
% rspEntry->getBalance().getFullText()
|
||||
% rspEntry->getLimitPeer().getFullText()
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -463,19 +480,23 @@ bool Pathfinder::findPaths(const unsigned int iMaxSteps, const unsigned int iMax
|
||||
bContinued = true;
|
||||
|
||||
cLog(lsTRACE) <<
|
||||
boost::str(boost::format("findPaths: push explore: %s/%s -> %s/%s")
|
||||
boost::str(boost::format("findPaths: push explore: %s/%s -> %s/%s balance=%s limit=%s limit_peer=%s")
|
||||
% STAmount::createHumanCurrency(speEnd.mCurrencyID)
|
||||
% RippleAddress::createHumanAccountID(speEnd.mAccountID)
|
||||
% STAmount::createHumanCurrency(speEnd.mCurrencyID)
|
||||
% RippleAddress::createHumanAccountID(uPeerID));
|
||||
% RippleAddress::createHumanAccountID(uPeerID)
|
||||
% rspEntry->getBalance().getFullText()
|
||||
% rspEntry->getLimit().getFullText()
|
||||
% rspEntry->getLimitPeer().getFullText());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// XXX Flip argument order to norm.
|
||||
// XXX Flip argument order to norm. (currency, issuer)
|
||||
std::vector<OrderBook::pointer> books;
|
||||
theApp->getOrderBookDB().getBooksByTakerPays(speEnd.mIssuerID, speEnd.mCurrencyID, books);
|
||||
|
||||
BOOST_FOREACH(OrderBook::ref book, books)
|
||||
{
|
||||
if (!spPath.hasSeen(ACCOUNT_XRP, book->getCurrencyOut(), book->getIssuerOut()))
|
||||
@@ -533,8 +554,10 @@ bool Pathfinder::findPaths(const unsigned int iMaxSteps, const unsigned int iMax
|
||||
TER terResult;
|
||||
|
||||
try {
|
||||
LedgerEntrySet lesSandbox(lesActive.duplicate());
|
||||
|
||||
terResult = RippleCalc::rippleCalc(
|
||||
lesActive,
|
||||
lesSandbox,
|
||||
saMaxAmountAct,
|
||||
saDstAmountAct,
|
||||
vpsExpanded,
|
||||
|
||||
@@ -1659,18 +1659,17 @@ void Peer::recvLedger(const boost::shared_ptr<ripple::TMLedgerData>& packet_ptr)
|
||||
return;
|
||||
}
|
||||
|
||||
uint256 hash;
|
||||
if(packet.ledgerhash().size() != 32)
|
||||
{
|
||||
cLog(lsWARNING) << "TX candidate reply with invalid hash size";
|
||||
punishPeer(LT_InvalidRequest);
|
||||
return;
|
||||
}
|
||||
memcpy(hash.begin(), packet.ledgerhash().data(), 32);
|
||||
|
||||
if (packet.type() == ripple::liTS_CANDIDATE)
|
||||
{ // got data for a candidate transaction set
|
||||
uint256 hash;
|
||||
if(packet.ledgerhash().size() != 32)
|
||||
{
|
||||
cLog(lsWARNING) << "TX candidate reply with invalid hash size";
|
||||
punishPeer(LT_InvalidRequest);
|
||||
return;
|
||||
}
|
||||
memcpy(hash.begin(), packet.ledgerhash().data(), 32);
|
||||
|
||||
|
||||
std::list<SHAMapNode> nodeIDs;
|
||||
std::list< std::vector<unsigned char> > nodeData;
|
||||
|
||||
@@ -1692,9 +1691,12 @@ void Peer::recvLedger(const boost::shared_ptr<ripple::TMLedgerData>& packet_ptr)
|
||||
return;
|
||||
}
|
||||
|
||||
theApp->getJobQueue().addJob(jtLEDGER_DATA, "gotLedgerData",
|
||||
BIND_TYPE(&LedgerAcquireMaster::gotLedgerData, &theApp->getMasterLedgerAcquire(),
|
||||
P_1, packet_ptr, boost::weak_ptr<Peer>(shared_from_this())));
|
||||
if (theApp->getMasterLedgerAcquire().awaitLedgerData(hash))
|
||||
theApp->getJobQueue().addJob(jtLEDGER_DATA, "gotLedgerData",
|
||||
BIND_TYPE(&LedgerAcquireMaster::gotLedgerData, &theApp->getMasterLedgerAcquire(),
|
||||
P_1, hash, packet_ptr, boost::weak_ptr<Peer>(shared_from_this())));
|
||||
else
|
||||
punishPeer(LT_UnwantedData);
|
||||
}
|
||||
|
||||
bool Peer::hasLedger(const uint256& hash) const
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
|
||||
#include "Pathfinder.h"
|
||||
#include "Log.h"
|
||||
#include "NetworkOPs.h"
|
||||
#include "RPCHandler.h"
|
||||
#include "RPCSub.h"
|
||||
#include "Application.h"
|
||||
@@ -1235,7 +1234,6 @@ Json::Value RPCHandler::doRipplePathFind(Json::Value jvRequest, int& cost)
|
||||
|
||||
cost = rpcCOST_EXPENSIVE;
|
||||
Ledger::pointer lSnapShot = boost::make_shared<Ledger>(boost::ref(*lpLedger), false);
|
||||
LedgerEntrySet lesSnapshot(lSnapShot, tapNONE);
|
||||
|
||||
ScopedUnlock su(theApp->getMasterLock()); // As long as we have a locked copy of the ledger, we can unlock.
|
||||
|
||||
@@ -1243,6 +1241,7 @@ Json::Value RPCHandler::doRipplePathFind(Json::Value jvRequest, int& cost)
|
||||
|
||||
for (unsigned int i=0; i != jvSrcCurrencies.size(); ++i) {
|
||||
Json::Value jvSource = jvSrcCurrencies[i];
|
||||
|
||||
uint160 uSrcCurrencyID;
|
||||
uint160 uSrcIssuerID;
|
||||
|
||||
@@ -1277,7 +1276,7 @@ Json::Value RPCHandler::doRipplePathFind(Json::Value jvRequest, int& cost)
|
||||
|
||||
if (!pf.findPaths(theConfig.PATH_SEARCH_SIZE, 3, spsComputed))
|
||||
{
|
||||
cLog(lsDEBUG) << "ripple_path_find: No paths found.";
|
||||
cLog(lsWARNING) << "ripple_path_find: No paths found.";
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1294,9 +1293,11 @@ Json::Value RPCHandler::doRipplePathFind(Json::Value jvRequest, int& cost)
|
||||
1);
|
||||
saMaxAmount.negate();
|
||||
|
||||
LedgerEntrySet lesSandbox(lSnapShot, tapNONE);
|
||||
|
||||
TER terResult =
|
||||
RippleCalc::rippleCalc(
|
||||
lesSnapshot,
|
||||
lesSandbox,
|
||||
saMaxAmountAct, // <--
|
||||
saDstAmountAct, // <--
|
||||
vpsExpanded, // <--
|
||||
@@ -1314,8 +1315,7 @@ Json::Value RPCHandler::doRipplePathFind(Json::Value jvRequest, int& cost)
|
||||
// cLog(lsDEBUG) << "ripple_path_find: PATHS IN: " << spsComputed.size() << " : " << spsComputed.getJson(0);
|
||||
// cLog(lsDEBUG) << "ripple_path_find: PATHS EXP: " << vpsExpanded.size();
|
||||
|
||||
|
||||
cLog(lsDEBUG)
|
||||
cLog(lsWARNING)
|
||||
<< boost::str(boost::format("ripple_path_find: saMaxAmount=%s saDstAmount=%s saMaxAmountAct=%s saDstAmountAct=%s")
|
||||
% saMaxAmount
|
||||
% saDstAmount
|
||||
@@ -1656,17 +1656,29 @@ Json::Value RPCHandler::doLedger(Json::Value jvRequest, int& cost)
|
||||
return ret;
|
||||
}
|
||||
|
||||
// { account: <account>, ledger: <integer> }
|
||||
// { account: <account>, ledger_min: <integer>, ledger_max: <integer> }
|
||||
// THIS ROUTINE DOESN'T SCALE.
|
||||
// FIXME: Require admin.
|
||||
// FIXME: Doesn't report database holes.
|
||||
// FIXME: For consistency change inputs to: ledger_index, ledger_index_min, ledger_index_max.
|
||||
// {
|
||||
// account: account,
|
||||
// ledger_index_min: ledger_index,
|
||||
// ledger_index_max: ledger_index,
|
||||
// binary: boolean, // optional, defaults to false
|
||||
// count: boolean, // optional, defaults to false
|
||||
// descending: boolean, // optional, defaults to false
|
||||
// offset: integer, // optional, defaults to 0
|
||||
// limit: integer // optional
|
||||
// }
|
||||
Json::Value RPCHandler::doAccountTransactions(Json::Value jvRequest, int& cost)
|
||||
{
|
||||
RippleAddress raAccount;
|
||||
uint32 minLedger;
|
||||
uint32 maxLedger;
|
||||
uint32 offset = jvRequest.isMember("offset") ? jvRequest["offset"].asUInt() : 0;
|
||||
int limit = jvRequest.isMember("limit") ? jvRequest["limit"].asUInt() : -1;
|
||||
bool bBinary = jvRequest.isMember("binary") && jvRequest["binary"].asBool();
|
||||
bool bDescending = jvRequest.isMember("descending") && jvRequest["descending"].asBool();
|
||||
bool bCount = jvRequest.isMember("count") && jvRequest["count"].asBool();
|
||||
uint32 uLedgerMin;
|
||||
uint32 uLedgerMax;
|
||||
uint32 uValidatedMin;
|
||||
uint32 uValidatedMax;
|
||||
bool bValidated = mNetOps->getValidatedRange(uValidatedMin, uValidatedMax);
|
||||
|
||||
if (!jvRequest.isMember("account"))
|
||||
return rpcError(rpcINVALID_PARAMS);
|
||||
@@ -1674,10 +1686,37 @@ Json::Value RPCHandler::doAccountTransactions(Json::Value jvRequest, int& cost)
|
||||
if (!raAccount.setAccountID(jvRequest["account"].asString()))
|
||||
return rpcError(rpcACT_MALFORMED);
|
||||
|
||||
if (jvRequest.isMember("ledger_min") && jvRequest.isMember("ledger_max"))
|
||||
// DEPRECATED
|
||||
if (jvRequest.isMember("ledger_min"))
|
||||
{
|
||||
minLedger = jvRequest["ledger_min"].asUInt();
|
||||
maxLedger = jvRequest["ledger_max"].asUInt();
|
||||
jvRequest["ledger_index_min"] = jvRequest["ledger_min"];
|
||||
bDescending = true;
|
||||
}
|
||||
|
||||
// DEPRECATED
|
||||
if (jvRequest.isMember("ledger_max"))
|
||||
{
|
||||
jvRequest["ledger_index_max"] = jvRequest["ledger_max"];
|
||||
bDescending = true;
|
||||
}
|
||||
|
||||
if (jvRequest.isMember("ledger_index_min") || jvRequest.isMember("ledger_index_max"))
|
||||
{
|
||||
int64 iLedgerMin = jvRequest.isMember("ledger_index_min") ? jvRequest["ledger_index_min"].asInt() : -1;
|
||||
int64 iLedgerMax = jvRequest.isMember("ledger_index_max") ? jvRequest["ledger_index_max"].asInt() : -1;
|
||||
|
||||
if (!bValidated && (iLedgerMin == -1 || iLedgerMax == -1)) {
|
||||
// Don't have a validated ledger range.
|
||||
return rpcError(rpcLGR_IDXS_INVALID);
|
||||
}
|
||||
|
||||
uLedgerMin = iLedgerMin == -1 ? uValidatedMin : iLedgerMin;
|
||||
uLedgerMax = iLedgerMax == -1 ? uValidatedMax : iLedgerMax;
|
||||
|
||||
if (uLedgerMax < uLedgerMin)
|
||||
{
|
||||
return rpcError(rpcLGR_IDXS_INVALID);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1685,65 +1724,74 @@ Json::Value RPCHandler::doAccountTransactions(Json::Value jvRequest, int& cost)
|
||||
Json::Value ret = lookupLedger(jvRequest, l);
|
||||
if (!l)
|
||||
return ret;
|
||||
minLedger = maxLedger = l->getLedgerSeq();
|
||||
}
|
||||
|
||||
if ((maxLedger < minLedger) || (maxLedger == 0))
|
||||
{
|
||||
return rpcError(rpcLGR_IDXS_INVALID);
|
||||
uLedgerMin = uLedgerMax = l->getLedgerSeq();
|
||||
}
|
||||
|
||||
#ifndef DEBUG
|
||||
try
|
||||
{
|
||||
#endif
|
||||
unsigned int vl = mNetOps->getValidatedSeq();
|
||||
ScopedUnlock su(theApp->getMasterLock());
|
||||
|
||||
Json::Value ret(Json::objectValue);
|
||||
|
||||
ret["account"] = raAccount.humanAccountID();
|
||||
|
||||
if (jvRequest.isMember("binary") && jvRequest["binary"].asBool())
|
||||
if (bBinary)
|
||||
{
|
||||
std::vector<NetworkOPs::txnMetaLedgerType> txns =
|
||||
mNetOps->getAccountTxsB(raAccount, minLedger, maxLedger);
|
||||
mNetOps->getAccountTxsB(raAccount, uLedgerMin, uLedgerMax, bDescending, offset, limit, mRole == ADMIN);
|
||||
|
||||
for (std::vector<NetworkOPs::txnMetaLedgerType>::const_iterator it = txns.begin(), end = txns.end();
|
||||
it != end; ++it)
|
||||
{
|
||||
Json::Value obj(Json::objectValue);
|
||||
obj["transaction"] = it->get<0>();
|
||||
obj["meta"] = it->get<1>();
|
||||
obj["inLedger"] = it->get<2>();
|
||||
if (it->get<2>() > vl)
|
||||
obj["validated"] = false;
|
||||
else if (mNetOps->haveLedger(it->get<2>()))
|
||||
obj["validated"] = true;
|
||||
ret["transactions"].append(obj);
|
||||
Json::Value jvObj(Json::objectValue);
|
||||
uint32 uLedgerIndex = it->get<2>();
|
||||
|
||||
jvObj["tx_blob"] = it->get<0>();
|
||||
jvObj["meta"] = it->get<1>();
|
||||
jvObj["ledger_index"] = uLedgerIndex;
|
||||
jvObj["validated"] = bValidated && uValidatedMin <= uLedgerIndex && uValidatedMax >= uLedgerIndex;
|
||||
|
||||
ret["transactions"].append(jvObj);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::vector< std::pair<Transaction::pointer, TransactionMetaSet::pointer> > txns = mNetOps->getAccountTxs(raAccount, minLedger, maxLedger);
|
||||
std::vector< std::pair<Transaction::pointer, TransactionMetaSet::pointer> > txns = mNetOps->getAccountTxs(raAccount, uLedgerMin, uLedgerMax, bDescending, offset, limit, mRole == ADMIN);
|
||||
|
||||
for (std::vector< std::pair<Transaction::pointer, TransactionMetaSet::pointer> >::iterator it = txns.begin(), end = txns.end(); it != end; ++it)
|
||||
{
|
||||
Json::Value obj(Json::objectValue);
|
||||
Json::Value jvObj(Json::objectValue);
|
||||
|
||||
if (it->first)
|
||||
obj["tx"] = it->first->getJson(1);
|
||||
jvObj["tx"] = it->first->getJson(1);
|
||||
|
||||
if (it->second)
|
||||
{
|
||||
obj["meta"] = it->second->getJson(0);
|
||||
uint32 uLedgerIndex = it->second->getLgrSeq();
|
||||
|
||||
uint32 s = it->second->getLgrSeq();
|
||||
if (s > vl)
|
||||
obj["validated"] = false;
|
||||
else if (mNetOps->haveLedger(s))
|
||||
obj["validated"] = true;
|
||||
jvObj["meta"] = it->second->getJson(0);
|
||||
jvObj["validated"] = bValidated && uValidatedMin <= uLedgerIndex && uValidatedMax >= uLedgerIndex;
|
||||
}
|
||||
|
||||
ret["transactions"].append(obj);
|
||||
ret["transactions"].append(jvObj);
|
||||
}
|
||||
}
|
||||
|
||||
//Add information about the original query
|
||||
ret["ledger_index_min"] = uLedgerMin;
|
||||
ret["ledger_index_max"] = uLedgerMax;
|
||||
ret["validated"] = bValidated && uValidatedMin <= uLedgerMin && uValidatedMax >= uLedgerMax;
|
||||
ret["offset"] = offset;
|
||||
|
||||
if (bCount)
|
||||
ret["count"] = mNetOps->countAccountTxs(raAccount, uLedgerMin, uLedgerMax);
|
||||
|
||||
if (jvRequest.isMember("limit"))
|
||||
ret["limit"] = limit;
|
||||
|
||||
|
||||
return ret;
|
||||
#ifndef DEBUG
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "RippleAddress.h"
|
||||
#include "SerializedTypes.h"
|
||||
#include "Ledger.h"
|
||||
#include "NetworkOPs.h"
|
||||
|
||||
#define LEDGER_CURRENT -1
|
||||
#define LEDGER_CLOSED -2
|
||||
|
||||
@@ -18,9 +18,16 @@
|
||||
#include "utils.h"
|
||||
#include "Log.h"
|
||||
#include "Serializer.h"
|
||||
#include "Application.h"
|
||||
|
||||
SETUP_LOG();
|
||||
|
||||
std::size_t hash_value(const CBase58Data& b58)
|
||||
{
|
||||
std::size_t seed = theApp->getNonceST() + (b58.nVersion * 0x9e3779b9);
|
||||
boost::hash_combine(seed, b58.vchData);
|
||||
return seed;
|
||||
}
|
||||
|
||||
RippleAddress::RippleAddress()
|
||||
{
|
||||
|
||||
@@ -250,9 +250,15 @@ TER PathState::pushNode(
|
||||
if (tesSUCCESS == terResult)
|
||||
{
|
||||
STAmount saOwed = lesEntries.rippleOwed(pnCur.uAccountID, pnBck.uAccountID, pnCur.uCurrencyID);
|
||||
STAmount saLimit;
|
||||
|
||||
if (!saOwed.isPositive() && -saOwed >= lesEntries.rippleLimit(pnCur.uAccountID, pnBck.uAccountID, pnCur.uCurrencyID))
|
||||
if (!saOwed.isPositive()
|
||||
&& -saOwed >= (saLimit = lesEntries.rippleLimit(pnCur.uAccountID, pnBck.uAccountID, pnCur.uCurrencyID)))
|
||||
{
|
||||
cLog(lsWARNING) << boost::str(boost::format("pushNode: dry: saOwed=%s saLimit=%s")
|
||||
% saOwed.getFullText()
|
||||
% saLimit.getFullText());
|
||||
|
||||
terResult = tecPATH_DRY;
|
||||
}
|
||||
}
|
||||
@@ -323,6 +329,8 @@ void PathState::setExpanded(
|
||||
const uint160 uOutIssuerID = saOutReq.getIssuer();
|
||||
const uint160 uSenderIssuerID = !!uMaxCurrencyID ? uSenderID : ACCOUNT_XRP; // Sender is always issuer for non-XRP.
|
||||
|
||||
// cLog(lsDEBUG) << boost::str(boost::format("setExpanded>"));
|
||||
|
||||
lesEntries = lesSource.duplicate();
|
||||
|
||||
terStatus = tesSUCCESS;
|
||||
@@ -344,7 +352,7 @@ void PathState::setExpanded(
|
||||
uMaxCurrencyID, // Max specifes the currency.
|
||||
uSenderIssuerID);
|
||||
|
||||
cLog(lsDEBUG) << boost::str(boost::format("PathState: pushed: account=%s currency=%s issuer=%s")
|
||||
cLog(lsDEBUG) << boost::str(boost::format("setExpanded: pushed: account=%s currency=%s issuer=%s")
|
||||
% RippleAddress::createHumanAccountID(uSenderID)
|
||||
% STAmount::createHumanCurrency(uMaxCurrencyID)
|
||||
% RippleAddress::createHumanAccountID(uSenderIssuerID));
|
||||
@@ -366,8 +374,10 @@ void PathState::setExpanded(
|
||||
: uOutIssuerID // Use implied node.
|
||||
: ACCOUNT_XRP;
|
||||
|
||||
cLog(lsDEBUG) << boost::str(boost::format("PathState: implied check: uNxtCurrencyID=%s uNxtAccountID=%s")
|
||||
% RippleAddress::createHumanAccountID(uNxtCurrencyID)
|
||||
cLog(lsDEBUG) << boost::str(boost::format("setExpanded: implied check: uMaxIssuerID=%s uSenderIssuerID=%s uNxtCurrencyID=%s uNxtAccountID=%s")
|
||||
% RippleAddress::createHumanAccountID(uMaxIssuerID)
|
||||
% RippleAddress::createHumanAccountID(uSenderIssuerID)
|
||||
% STAmount::createHumanCurrency(uNxtCurrencyID)
|
||||
% RippleAddress::createHumanAccountID(uNxtAccountID));
|
||||
|
||||
// Can't just use push implied, because it can't compensate for next account.
|
||||
@@ -375,9 +385,9 @@ void PathState::setExpanded(
|
||||
|| uMaxCurrencyID != uNxtCurrencyID // Next is different currency, offer next...
|
||||
|| uMaxIssuerID != uNxtAccountID) // Next is not implied issuer
|
||||
{
|
||||
cLog(lsDEBUG) << boost::str(boost::format("PathState: sender implied: account=%s currency=%s issuer=%s")
|
||||
cLog(lsDEBUG) << boost::str(boost::format("setExpanded: sender implied: account=%s currency=%s issuer=%s")
|
||||
% RippleAddress::createHumanAccountID(uMaxIssuerID)
|
||||
% RippleAddress::createHumanAccountID(uMaxCurrencyID)
|
||||
% STAmount::createHumanCurrency(uMaxCurrencyID)
|
||||
% RippleAddress::createHumanAccountID(uMaxIssuerID));
|
||||
// Add account implied by SendMax.
|
||||
terStatus = pushNode(
|
||||
@@ -394,7 +404,7 @@ void PathState::setExpanded(
|
||||
{
|
||||
if (tesSUCCESS == terStatus)
|
||||
{
|
||||
cLog(lsDEBUG) << boost::str(boost::format("PathState: element in path:"));
|
||||
cLog(lsDEBUG) << boost::str(boost::format("setExpanded: element in path:"));
|
||||
terStatus = pushNode(speElement.getNodeType(), speElement.getAccountID(), speElement.getCurrency(), speElement.getIssuerID());
|
||||
}
|
||||
}
|
||||
@@ -408,9 +418,9 @@ void PathState::setExpanded(
|
||||
|| pnPrv.uAccountID != uOutIssuerID)) // Need the implied issuer.
|
||||
{
|
||||
// Add implied account.
|
||||
cLog(lsDEBUG) << boost::str(boost::format("PathState: receiver implied: account=%s currency=%s issuer=%s")
|
||||
cLog(lsDEBUG) << boost::str(boost::format("setExpanded: receiver implied: account=%s currency=%s issuer=%s")
|
||||
% RippleAddress::createHumanAccountID(uOutIssuerID)
|
||||
% RippleAddress::createHumanAccountID(uOutCurrencyID)
|
||||
% STAmount::createHumanCurrency(uOutCurrencyID)
|
||||
% RippleAddress::createHumanAccountID(uOutIssuerID));
|
||||
terStatus = pushNode(
|
||||
!!uOutCurrencyID
|
||||
@@ -449,7 +459,7 @@ void PathState::setExpanded(
|
||||
if (!umForward.insert(std::make_pair(boost::make_tuple(pnCur.uAccountID, pnCur.uCurrencyID, pnCur.uIssuerID), uNode)).second)
|
||||
{
|
||||
// Failed to insert. Have a loop.
|
||||
cLog(lsDEBUG) << boost::str(boost::format("PathState: loop detected: %s")
|
||||
cLog(lsDEBUG) << boost::str(boost::format("setExpanded: loop detected: %s")
|
||||
% getJson());
|
||||
|
||||
terStatus = temBAD_PATH_LOOP;
|
||||
@@ -457,7 +467,7 @@ void PathState::setExpanded(
|
||||
}
|
||||
}
|
||||
|
||||
cLog(lsDEBUG) << boost::str(boost::format("PathState: in=%s/%s out=%s/%s %s")
|
||||
cLog(lsDEBUG) << boost::str(boost::format("setExpanded: in=%s/%s out=%s/%s %s")
|
||||
% STAmount::createHumanCurrency(uMaxCurrencyID)
|
||||
% RippleAddress::createHumanAccountID(uMaxIssuerID)
|
||||
% STAmount::createHumanCurrency(uOutCurrencyID)
|
||||
@@ -2612,6 +2622,10 @@ TER RippleCalc::rippleCalc(
|
||||
{
|
||||
RippleCalc rc(lesActive, bOpenLedger);
|
||||
|
||||
cLog(lsTRACE) << boost::str(boost::format("rippleCalc> saMaxAmountReq=%s saDstAmountReq=%s")
|
||||
% saMaxAmountReq.getFullText()
|
||||
% saDstAmountReq.getFullText());
|
||||
|
||||
TER terResult = temUNCERTAIN;
|
||||
|
||||
// YYY Might do basic checks on src and dst validity as per doPayment.
|
||||
@@ -2669,6 +2683,12 @@ int iIndex = 0;
|
||||
if (!pspExpanded)
|
||||
return temUNKNOWN;
|
||||
|
||||
cLog(lsTRACE) << boost::str(boost::format("rippleCalc: EXPAND: saDstAmountReq=%s saMaxAmountReq=%s uDstAccountID=%s uSrcAccountID=%s")
|
||||
% saDstAmountReq.getFullText()
|
||||
% saMaxAmountReq.getFullText()
|
||||
% RippleAddress::createHumanAccountID(uDstAccountID)
|
||||
% RippleAddress::createHumanAccountID(uSrcAccountID));
|
||||
|
||||
pspExpanded->setExpanded(lesActive, spPath, uDstAccountID, uSrcAccountID);
|
||||
|
||||
cLog(lsDEBUG) << boost::str(boost::format("rippleCalc: Build path: %d: status: %s")
|
||||
@@ -2764,6 +2784,7 @@ int iPass = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (sLog(lsDEBUG))
|
||||
{
|
||||
cLog(lsDEBUG) << boost::str(boost::format("rippleCalc: Summary: Pass: %d Dry: %d Paths: %d") % ++iPass % iDry % vpsExpanded.size());
|
||||
@@ -3003,7 +3024,7 @@ void TransactionEngine::calcOfferBridgeNext(
|
||||
{
|
||||
// Offer must be redeeming IOUs.
|
||||
|
||||
// No additional
|
||||
// No additional
|
||||
// XXX Broken
|
||||
}
|
||||
|
||||
|
||||
@@ -209,8 +209,8 @@ public:
|
||||
const bool bPartialPayment,
|
||||
const bool bLimitQuality,
|
||||
const bool bNoRippleDirect,
|
||||
const bool bStandAlone,
|
||||
const bool bOpenLedger = true
|
||||
const bool bStandAlone, // --> True, not to affect accounts.
|
||||
const bool bOpenLedger = true // --> What kind of errors to return.
|
||||
);
|
||||
|
||||
static void setCanonical(STPathSet& spsDst, const std::vector<PathState::pointer>& vpsExpanded, bool bKeepDefault);
|
||||
|
||||
@@ -15,6 +15,10 @@
|
||||
#include "SHAMap.h"
|
||||
#include "Application.h"
|
||||
|
||||
#ifndef STATE_MAP_BUCKETS
|
||||
#define STATE_MAP_BUCKETS 1024
|
||||
#endif
|
||||
|
||||
SETUP_LOG();
|
||||
|
||||
DECLARE_INSTANCE(SHAMap);
|
||||
@@ -52,6 +56,8 @@ std::size_t hash_value(const uint160& u)
|
||||
|
||||
SHAMap::SHAMap(SHAMapType t, uint32 seq) : mSeq(seq), mState(smsModifying), mType(t)
|
||||
{
|
||||
if (t == smtSTATE)
|
||||
mTNByID.rehash(STATE_MAP_BUCKETS);
|
||||
root = boost::make_shared<SHAMapTreeNode>(mSeq, SHAMapNode(0, uint256()));
|
||||
root->makeInner();
|
||||
mTNByID[*root] = root;
|
||||
@@ -59,6 +65,8 @@ SHAMap::SHAMap(SHAMapType t, uint32 seq) : mSeq(seq), mState(smsModifying), mTyp
|
||||
|
||||
SHAMap::SHAMap(SHAMapType t, const uint256& hash) : mSeq(1), mState(smsSynching), mType(t)
|
||||
{ // FIXME: Need to acquire root node
|
||||
if (t == smtSTATE)
|
||||
mTNByID.rehash(STATE_MAP_BUCKETS);
|
||||
root = boost::make_shared<SHAMapTreeNode>(mSeq, SHAMapNode(0, uint256()));
|
||||
root->makeInner();
|
||||
mTNByID[*root] = root;
|
||||
@@ -205,10 +213,10 @@ SHAMapTreeNode::pointer SHAMap::getNode(const SHAMapNode& id, const uint256& has
|
||||
#ifdef DEBUG
|
||||
if (node->getNodeHash() != hash)
|
||||
{
|
||||
std::cerr << "Attempt to get node, hash not in tree" << std::endl;
|
||||
std::cerr << "ID: " << id << std::endl;
|
||||
std::cerr << "TgtHash " << hash << std::endl;
|
||||
std::cerr << "NodHash " << node->getNodeHash() << std::endl;
|
||||
cLog(lsFATAL) << "Attempt to get node, hash not in tree";
|
||||
cLog(lsFATAL) << "ID: " << id;
|
||||
cLog(lsFATAL) << "TgtHash " << hash;
|
||||
cLog(lsFATAL) << "NodHash " << node->getNodeHash();
|
||||
throw std::runtime_error("invalid node");
|
||||
}
|
||||
#endif
|
||||
@@ -264,9 +272,6 @@ SHAMapItem::SHAMapItem(const uint256& tag, const Serializer& data)
|
||||
SHAMapTreeNode* SHAMap::firstBelow(SHAMapTreeNode* node)
|
||||
{
|
||||
// Return the first item below this node
|
||||
#ifdef ST_DEBUG
|
||||
std::cerr << "firstBelow(" << *node << ")" << std::endl;
|
||||
#endif
|
||||
do
|
||||
{ // Walk down the tree
|
||||
if (node->hasItem()) return node;
|
||||
@@ -275,11 +280,6 @@ SHAMapTreeNode* SHAMap::firstBelow(SHAMapTreeNode* node)
|
||||
for (int i = 0; i < 16; ++i)
|
||||
if (!node->isEmptyBranch(i))
|
||||
{
|
||||
#ifdef ST_DEBUG
|
||||
std::cerr << " FB: node " << *node << std::endl;
|
||||
std::cerr << " has non-empty branch " << i << " : " <<
|
||||
node->getChildNodeID(i) << ", " << node->getChildHash(i) << std::endl;
|
||||
#endif
|
||||
node = getNodePointer(node->getChildNodeID(i), node->getChildHash(i));
|
||||
foundNode = true;
|
||||
break;
|
||||
@@ -291,10 +291,6 @@ SHAMapTreeNode* SHAMap::firstBelow(SHAMapTreeNode* node)
|
||||
|
||||
SHAMapTreeNode* SHAMap::lastBelow(SHAMapTreeNode* node)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
std::cerr << "lastBelow(" << *node << ")" << std::endl;
|
||||
#endif
|
||||
|
||||
do
|
||||
{ // Walk down the tree
|
||||
if (node->hasItem())
|
||||
@@ -330,7 +326,7 @@ SHAMapItem::pointer SHAMap::onlyBelow(SHAMapTreeNode* node)
|
||||
|
||||
if (!nextNode)
|
||||
{
|
||||
std::cerr << *node << std::endl;
|
||||
cLog(lsFATAL) << *node;
|
||||
assert(false);
|
||||
return SHAMapItem::pointer();
|
||||
}
|
||||
@@ -542,9 +538,6 @@ bool SHAMap::delItem(const uint256& id)
|
||||
int bc = node->getBranchCount();
|
||||
if (bc == 0)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
std::cerr << "delItem makes empty node" << std::endl;
|
||||
#endif
|
||||
prevHash=uint256();
|
||||
if (!mTNByID.erase(*node))
|
||||
assert(false);
|
||||
@@ -556,9 +549,6 @@ bool SHAMap::delItem(const uint256& id)
|
||||
{
|
||||
returnNode(node, true);
|
||||
eraseChildren(node);
|
||||
#ifdef ST_DEBUG
|
||||
std::cerr << "Making item node " << *node << std::endl;
|
||||
#endif
|
||||
node->setItem(item, type);
|
||||
}
|
||||
prevHash = node->getNodeHash();
|
||||
@@ -577,10 +567,6 @@ bool SHAMap::delItem(const uint256& id)
|
||||
|
||||
bool SHAMap::addGiveItem(SHAMapItem::ref item, bool isTransaction, bool hasMeta)
|
||||
{ // add the specified item, does not update
|
||||
#ifdef ST_DEBUG
|
||||
std::cerr << "aGI " << item->getTag() << std::endl;
|
||||
#endif
|
||||
|
||||
uint256 tag = item->getTag();
|
||||
SHAMapTreeNode::TNType type = !isTransaction ? SHAMapTreeNode::tnACCOUNT_STATE :
|
||||
(hasMeta ? SHAMapTreeNode::tnTRANSACTION_MD : SHAMapTreeNode::tnTRANSACTION_NM);
|
||||
@@ -603,17 +589,14 @@ bool SHAMap::addGiveItem(SHAMapItem::ref item, bool isTransaction, bool hasMeta)
|
||||
|
||||
if (node->isInner())
|
||||
{ // easy case, we end on an inner node
|
||||
#ifdef ST_DEBUG
|
||||
std::cerr << "aGI inner " << *node << std::endl;
|
||||
#endif
|
||||
int branch = node->selectBranch(tag);
|
||||
assert(node->isEmptyBranch(branch));
|
||||
SHAMapTreeNode::pointer newNode =
|
||||
boost::make_shared<SHAMapTreeNode>(node->getChildNodeID(branch), item, type, mSeq);
|
||||
if (!mTNByID.emplace(SHAMapNode(*newNode), newNode).second)
|
||||
{
|
||||
std::cerr << "Node: " << *node << std::endl;
|
||||
std::cerr << "NewNode: " << *newNode << std::endl;
|
||||
cLog(lsFATAL) << "Node: " << *node;
|
||||
cLog(lsFATAL) << "NewNode: " << *newNode;
|
||||
dump();
|
||||
assert(false);
|
||||
throw std::runtime_error("invalid inner node");
|
||||
@@ -623,10 +606,6 @@ bool SHAMap::addGiveItem(SHAMapItem::ref item, bool isTransaction, bool hasMeta)
|
||||
}
|
||||
else
|
||||
{ // this is a leaf node that has to be made an inner node holding two items
|
||||
#ifdef ST_DEBUG
|
||||
std::cerr << "aGI leaf " << *node << std::endl;
|
||||
std::cerr << "Existing: " << node->peekItem()->getTag() << std::endl;
|
||||
#endif
|
||||
SHAMapItem::pointer otherItem = node->peekItem();
|
||||
assert(otherItem && (tag != otherItem->getTag()));
|
||||
|
||||
@@ -636,10 +615,6 @@ bool SHAMap::addGiveItem(SHAMapItem::ref item, bool isTransaction, bool hasMeta)
|
||||
|
||||
while ((b1 = node->selectBranch(tag)) == (b2 = node->selectBranch(otherItem->getTag())))
|
||||
{ // we need a new inner node, since both go on same branch at this level
|
||||
#ifdef ST_DEBUG
|
||||
std::cerr << "need new inner node at " << node->getDepth() << ", "
|
||||
<< b1 << "==" << b2 << std::endl;
|
||||
#endif
|
||||
SHAMapTreeNode::pointer newNode =
|
||||
boost::make_shared<SHAMapTreeNode>(mSeq, node->getChildNodeID(b1));
|
||||
newNode->makeInner();
|
||||
@@ -711,7 +686,7 @@ bool SHAMap::updateGiveItem(SHAMapItem::ref item, bool isTransaction, bool hasMe
|
||||
|
||||
void SHAMapItem::dump()
|
||||
{
|
||||
std::cerr << "SHAMapItem(" << mTag << ") " << mData.size() << "bytes" << std::endl;
|
||||
cLog(lsINFO) << "SHAMapItem(" << mTag << ") " << mData.size() << "bytes";
|
||||
}
|
||||
|
||||
SHAMapTreeNode::pointer SHAMap::fetchNodeExternal(const SHAMapNode& id, const uint256& hash)
|
||||
@@ -729,7 +704,7 @@ SHAMapTreeNode::pointer SHAMap::fetchNodeExternal(const SHAMapNode& id, const ui
|
||||
try
|
||||
{
|
||||
SHAMapTreeNode::pointer ret =
|
||||
boost::make_shared<SHAMapTreeNode>(id, obj->getData(), mSeq, snfPREFIX, hash);
|
||||
boost::make_shared<SHAMapTreeNode>(id, obj->getData(), mSeq, snfPREFIX, hash, true);
|
||||
if (id != *ret)
|
||||
{
|
||||
cLog(lsFATAL) << "id:" << id << ", got:" << *ret;
|
||||
@@ -880,25 +855,13 @@ void SHAMap::dropCache()
|
||||
|
||||
void SHAMap::dump(bool hash)
|
||||
{
|
||||
#if 0
|
||||
std::cerr << "SHAMap::dump" << std::endl;
|
||||
SHAMapItem::pointer i=peekFirstItem();
|
||||
while (i)
|
||||
{
|
||||
std::cerr << "Item: id=" << i->getTag() << std::endl;
|
||||
i = peekNextItem(i->getTag());
|
||||
}
|
||||
std::cerr << "SHAMap::dump done" << std::endl;
|
||||
#endif
|
||||
|
||||
std::cerr << " MAP Contains" << std::endl;
|
||||
cLog(lsINFO) << " MAP Contains";
|
||||
boost::recursive_mutex::scoped_lock sl(mLock);
|
||||
for(boost::unordered_map<SHAMapNode, SHAMapTreeNode::pointer>::iterator it = mTNByID.begin();
|
||||
it != mTNByID.end(); ++it)
|
||||
{
|
||||
std::cerr << it->second->getString() << std::endl;
|
||||
if (hash)
|
||||
std::cerr << " " << it->second->getNodeHash() << std::endl;
|
||||
cLog(lsINFO) << it->second->getString();
|
||||
tLog(hash, lsINFO) << it->second->getNodeHash();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -187,7 +187,7 @@ public:
|
||||
|
||||
// raw node functions
|
||||
SHAMapTreeNode(const SHAMapNode& id, const std::vector<unsigned char>& data, uint32 seq,
|
||||
SHANodeFormat format, const uint256& hash);
|
||||
SHANodeFormat format, const uint256& hash, bool hashValid);
|
||||
void addRaw(Serializer &, SHANodeFormat format);
|
||||
|
||||
virtual bool isPopulated() const { return true; }
|
||||
|
||||
@@ -177,7 +177,7 @@ SHAMapTreeNode::SHAMapTreeNode(const SHAMapNode& node, SHAMapItem::ref item, TNT
|
||||
}
|
||||
|
||||
SHAMapTreeNode::SHAMapTreeNode(const SHAMapNode& id, const std::vector<unsigned char>& rawNode, uint32 seq,
|
||||
SHANodeFormat format, const uint256& hash) :
|
||||
SHANodeFormat format, const uint256& hash, bool hashValid) :
|
||||
SHAMapNode(id), mSeq(seq), mType(tnERROR), mIsBranch(0), mFullBelow(false)
|
||||
{
|
||||
if (format == snfWIRE)
|
||||
@@ -317,9 +317,7 @@ SHAMapTreeNode::SHAMapTreeNode(const SHAMapNode& id, const std::vector<unsigned
|
||||
throw std::runtime_error("Unknown format");
|
||||
}
|
||||
|
||||
if (hash.isZero())
|
||||
updateHash();
|
||||
else
|
||||
if (hashValid)
|
||||
{
|
||||
mHash = hash;
|
||||
#ifdef PARANOID
|
||||
@@ -327,6 +325,8 @@ SHAMapTreeNode::SHAMapTreeNode(const SHAMapNode& id, const std::vector<unsigned
|
||||
assert(mHash == hash);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
updateHash();
|
||||
}
|
||||
|
||||
bool SHAMapTreeNode::updateHash()
|
||||
|
||||
@@ -13,6 +13,8 @@
|
||||
|
||||
SETUP_LOG();
|
||||
|
||||
static const uint256 uZero;
|
||||
|
||||
void SHAMap::getMissingNodes(std::vector<SHAMapNode>& nodeIDs, std::vector<uint256>& hashes, int max,
|
||||
SHAMapSyncFilter* filter)
|
||||
{
|
||||
@@ -63,7 +65,7 @@ void SHAMap::getMissingNodes(std::vector<SHAMapNode>& nodeIDs, std::vector<uint2
|
||||
{
|
||||
assert(mSeq >= 1);
|
||||
SHAMapTreeNode::pointer ptr =
|
||||
boost::make_shared<SHAMapTreeNode>(childID, nodeData, mSeq - 1, snfPREFIX, childHash);
|
||||
boost::make_shared<SHAMapTreeNode>(childID, nodeData, mSeq - 1, snfPREFIX, childHash, true);
|
||||
cLog(lsTRACE) << "Got sync node from cache: " << *ptr;
|
||||
mTNByID[*ptr] = ptr;
|
||||
d = ptr.get();
|
||||
@@ -213,7 +215,7 @@ SMAddNode SHAMap::addRootNode(const std::vector<unsigned char>& rootNode, SHANod
|
||||
|
||||
assert(mSeq >= 1);
|
||||
SHAMapTreeNode::pointer node =
|
||||
boost::make_shared<SHAMapTreeNode>(SHAMapNode(), rootNode, mSeq - 1, format, uint256());
|
||||
boost::make_shared<SHAMapTreeNode>(SHAMapNode(), rootNode, mSeq - 1, format, uZero, false);
|
||||
if (!node)
|
||||
return SMAddNode::invalid();
|
||||
|
||||
@@ -253,7 +255,7 @@ SMAddNode SHAMap::addRootNode(const uint256& hash, const std::vector<unsigned ch
|
||||
|
||||
assert(mSeq >= 1);
|
||||
SHAMapTreeNode::pointer node =
|
||||
boost::make_shared<SHAMapTreeNode>(SHAMapNode(), rootNode, mSeq - 1, format, uint256());
|
||||
boost::make_shared<SHAMapTreeNode>(SHAMapNode(), rootNode, mSeq - 1, format, uZero, false);
|
||||
if (!node || node->getNodeHash() != hash)
|
||||
return SMAddNode::invalid();
|
||||
|
||||
@@ -332,7 +334,7 @@ SMAddNode SHAMap::addKnownNode(const SHAMapNode& node, const std::vector<unsigne
|
||||
|
||||
assert(mSeq >= 1);
|
||||
SHAMapTreeNode::pointer newNode =
|
||||
boost::make_shared<SHAMapTreeNode>(node, rawNode, mSeq - 1, snfWIRE, uint256());
|
||||
boost::make_shared<SHAMapTreeNode>(node, rawNode, mSeq - 1, snfWIRE, uZero, false);
|
||||
if (hash != newNode->getNodeHash()) // these aren't the droids we're looking for
|
||||
return SMAddNode::invalid();
|
||||
|
||||
|
||||
11
src/cpp/ripple/TransactionCheck.cpp
Normal file
11
src/cpp/ripple/TransactionCheck.cpp
Normal file
@@ -0,0 +1,11 @@
|
||||
|
||||
#include "TransactionErr.h"
|
||||
#include "TransactionEngine.h"
|
||||
|
||||
// Double check a transaction's metadata to make sure no system invariants were broken
|
||||
// Call right before 'calcRawMeta'
|
||||
|
||||
bool TransactionEngine::checkInvariants(TER result, const SerializedTransaction& txn, TransactionEngineParams params)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@@ -93,7 +93,7 @@ TER TransactionEngine::applyTransaction(const SerializedTransaction& txn, Transa
|
||||
}
|
||||
#endif
|
||||
|
||||
UPTR_T<Transactor> transactor = Transactor::makeTransactor(txn,params,this);
|
||||
UPTR_T<Transactor> transactor = Transactor::makeTransactor(txn, params, this);
|
||||
if (transactor.get() != NULL)
|
||||
{
|
||||
uint256 txID = txn.getTransactionID();
|
||||
@@ -153,28 +153,40 @@ TER TransactionEngine::applyTransaction(const SerializedTransaction& txn, Transa
|
||||
|
||||
if (didApply)
|
||||
{
|
||||
// Transaction succeeded fully or (retries are not allowed and the transaction could claim a fee)
|
||||
Serializer m;
|
||||
mNodes.calcRawMeta(m, terResult, mTxnSeq++);
|
||||
|
||||
txnWrite();
|
||||
|
||||
Serializer s;
|
||||
txn.add(s);
|
||||
|
||||
if (isSetBit(params, tapOPEN_LEDGER))
|
||||
if (!checkInvariants(terResult, txn, params))
|
||||
{
|
||||
if (!mLedger->addTransaction(txID, s))
|
||||
assert(false);
|
||||
cLog(lsFATAL) << "Transaction violates invariants";
|
||||
cLog(lsFATAL) << txn.getJson(0);
|
||||
cLog(lsFATAL) << transToken(terResult) << ": " << transHuman(terResult);
|
||||
cLog(lsFATAL) << mNodes.getJson(0);
|
||||
didApply = false;
|
||||
terResult = tefINTERNAL;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!mLedger->addTransaction(txID, s, m))
|
||||
// Transaction succeeded fully or (retries are not allowed and the transaction could claim a fee)
|
||||
Serializer m;
|
||||
mNodes.calcRawMeta(m, terResult, mTxnSeq++);
|
||||
|
||||
txnWrite();
|
||||
|
||||
Serializer s;
|
||||
txn.add(s);
|
||||
|
||||
if (isSetBit(params, tapOPEN_LEDGER))
|
||||
{
|
||||
if (!mLedger->addTransaction(txID, s))
|
||||
assert(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!mLedger->addTransaction(txID, s, m))
|
||||
assert(false);
|
||||
|
||||
// Charge whatever fee they specified.
|
||||
STAmount saPaid = txn.getTransactionFee();
|
||||
mLedger->destroyCoins(saPaid.getNValue());
|
||||
// Charge whatever fee they specified.
|
||||
STAmount saPaid = txn.getTransactionFee();
|
||||
mLedger->destroyCoins(saPaid.getNValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -65,6 +65,7 @@ public:
|
||||
void entryModify(SLE::ref sleEntry) { mNodes.entryModify(sleEntry); }
|
||||
|
||||
TER applyTransaction(const SerializedTransaction&, TransactionEngineParams, bool& didApply);
|
||||
bool checkInvariants(TER result, const SerializedTransaction& txn, TransactionEngineParams params);
|
||||
};
|
||||
|
||||
inline TransactionEngineParams operator|(const TransactionEngineParams& l1, const TransactionEngineParams& l2)
|
||||
|
||||
@@ -38,6 +38,7 @@ bool transResultInfo(TER terCode, std::string& strToken, std::string& strHuman)
|
||||
{ tefGEN_IN_USE, "tefGEN_IN_USE", "Generator already in use." },
|
||||
{ tefNO_AUTH_REQUIRED, "tefNO_AUTH_REQUIRED", "Auth is not required." },
|
||||
{ tefPAST_SEQ, "tefPAST_SEQ", "This sequence number has already past." },
|
||||
{ tefINTERNAL, "tefINTERNAL", "Internal error." },
|
||||
|
||||
{ telLOCAL_ERROR, "telLOCAL_ERROR", "Local failure." },
|
||||
{ telBAD_DOMAIN, "telBAD_DOMAIN", "Domain too long." },
|
||||
|
||||
@@ -81,6 +81,7 @@ enum TER // aka TransactionEngineResult
|
||||
tefGEN_IN_USE,
|
||||
tefNO_AUTH_REQUIRED, // Can't set auth if auth is not required.
|
||||
tefPAST_SEQ,
|
||||
tefINTERNAL,
|
||||
|
||||
// -99 .. -1: R Retry (sequence too high, no funds for txn fee, originating account non-existent)
|
||||
// Causes:
|
||||
|
||||
@@ -164,11 +164,8 @@ protected:
|
||||
unsigned char nVersion;
|
||||
std::vector<unsigned char> vchData;
|
||||
|
||||
CBase58Data()
|
||||
{
|
||||
nVersion = 1;
|
||||
vchData.clear();
|
||||
}
|
||||
CBase58Data() : nVersion(1)
|
||||
{ ; }
|
||||
|
||||
~CBase58Data()
|
||||
{
|
||||
@@ -247,13 +244,7 @@ public:
|
||||
friend std::size_t hash_value(const CBase58Data& b58);
|
||||
};
|
||||
|
||||
inline std::size_t hash_value(const CBase58Data& b58)
|
||||
{
|
||||
std::size_t seed = boost::hash_value(b58.nVersion);
|
||||
extern std::size_t hash_value(const CBase58Data& b58);
|
||||
|
||||
boost::hash_combine(seed, b58.vchData);
|
||||
|
||||
return seed;
|
||||
}
|
||||
#endif
|
||||
// vim:ts=4
|
||||
|
||||
@@ -70,11 +70,10 @@ void printHelp(const po::options_description& desc)
|
||||
cerr << desc << endl;
|
||||
|
||||
cerr << "Commands: " << endl;
|
||||
cerr << " account_info <account>|<nickname>" << endl;
|
||||
cerr << " account_info <seed>|<pass_phrase>|<key> [<index>]" << endl;
|
||||
cerr << " account_lines <account>|<nickname>|<account_public_key> [<index>]" << endl;
|
||||
cerr << " account_offers <account>|<nickname>|<account_public_key> [<index>]" << endl;
|
||||
cerr << " account_tx <account>|<nickname>|<account_public_key> <ledger>|(<minledger> <maxledger>)" << endl;
|
||||
cerr << " account_info <account>|<nickname>|<seed>|<pass_phrase>|<key> [<ledger>]" << endl;
|
||||
cerr << " account_lines <account>|<nickname>|<account_public_key> [<ledger>]" << endl;
|
||||
cerr << " account_offers <account>|<nickname>|<account_public_key> [<ledger>]" << endl;
|
||||
cerr << " account_tx accountID [ledger_min [ledger_max [limit [offset]]]] [binary] [count] [descending]" << endl;
|
||||
cerr << " book_offers <taker_pays> <taker_gets> [<taker [<ledger> [<limit> [<proof> [<marker>]]]]]" << endl;
|
||||
cerr << " connect <ip> [<port>]" << endl;
|
||||
cerr << " consensus_info" << endl;
|
||||
@@ -188,8 +187,17 @@ int main(int argc, char* argv[])
|
||||
}
|
||||
}
|
||||
|
||||
if (iResult)
|
||||
{
|
||||
nothing();
|
||||
}
|
||||
else if (vm.count("help"))
|
||||
{
|
||||
iResult = 1;
|
||||
}
|
||||
|
||||
if (HaveSustain() &&
|
||||
!vm.count("parameters") && !vm.count("fg") && !vm.count("standalone") && !vm.count("unittest"))
|
||||
!iResult && !vm.count("parameters") && !vm.count("fg") && !vm.count("standalone") && !vm.count("unittest"))
|
||||
{
|
||||
std::string logMe = DoSustain();
|
||||
if (!logMe.empty())
|
||||
@@ -251,16 +259,13 @@ int main(int argc, char* argv[])
|
||||
{
|
||||
nothing();
|
||||
}
|
||||
else if (vm.count("help"))
|
||||
{
|
||||
iResult = 1;
|
||||
}
|
||||
else if (!vm.count("parameters"))
|
||||
{
|
||||
// No arguments. Run server.
|
||||
setupServer();
|
||||
NameThread("io");
|
||||
startServer();
|
||||
InstanceType::shutdown();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -4,6 +4,10 @@
|
||||
#include <sys/prctl.h>
|
||||
#include <sys/wait.h>
|
||||
#endif
|
||||
#ifdef __FreeBSD__
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#endif
|
||||
|
||||
#include <fstream>
|
||||
|
||||
@@ -20,6 +24,9 @@
|
||||
|
||||
void getRand(unsigned char *buf, int num)
|
||||
{
|
||||
#ifdef PURIFY
|
||||
memset(buf, 0, num);
|
||||
#endif
|
||||
if (RAND_bytes(buf, num) != 1)
|
||||
{
|
||||
assert(false);
|
||||
@@ -336,8 +343,8 @@ uint32_t htobe32(uint32_t value)
|
||||
}
|
||||
|
||||
uint32_t be32toh(uint32_t value)
|
||||
{
|
||||
return( _byteswap_ulong(value));
|
||||
{
|
||||
return( _byteswap_ulong(value));
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -443,8 +450,8 @@ std::string DoSustain()
|
||||
#else
|
||||
|
||||
bool HaveSustain() { return false; }
|
||||
std::string DoSustain() { return std::string; }
|
||||
std::string StopSustain() { return std::string; }
|
||||
std::string DoSustain() { return std::string(); }
|
||||
std::string StopSustain() { return std::string(); }
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ Network.protocol.start = function () {
|
||||
|
||||
};
|
||||
|
||||
// Target state: disconnectted
|
||||
// Target state: disconnect
|
||||
Network.protocol.stop = function () {
|
||||
|
||||
};
|
||||
|
||||
@@ -192,7 +192,8 @@ Server.prototype.stop = function () {
|
||||
if (!self.quiet) console.log("server: stop: server exited");
|
||||
|
||||
self.emit('stopped');
|
||||
delete this.child;
|
||||
|
||||
delete self.child;
|
||||
});
|
||||
|
||||
this.child.kill();
|
||||
|
||||
@@ -129,14 +129,14 @@ var build_teardown = function (host) {
|
||||
.connect(false);
|
||||
},
|
||||
function stopServerStep(callback) {
|
||||
|
||||
if (opts.no_server)
|
||||
{
|
||||
return callback();
|
||||
}
|
||||
|
||||
return callback();
|
||||
}
|
||||
|
||||
data.server.on('stopped', callback).stop();
|
||||
data.server
|
||||
.on('stopped', callback)
|
||||
.stop();
|
||||
}
|
||||
], done);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user