mirror of
https://github.com/Xahau/xahaud.git
synced 2025-12-06 17:27:52 +00:00
Merge branch 'master' into websocket
Conflicts: src/Config.h
This commit is contained in:
37
deploy/cointoss.nsi
Normal file
37
deploy/cointoss.nsi
Normal file
@@ -0,0 +1,37 @@
|
||||
Name "CoinToss"
|
||||
|
||||
; The file to write
|
||||
OutFile "toss install.exe"
|
||||
|
||||
; The default installation directory
|
||||
InstallDir "$PROGRAMFILES\CoinToss"
|
||||
|
||||
; Request application privileges for Windows Vista
|
||||
RequestExecutionLevel user
|
||||
|
||||
;--------------------------------
|
||||
|
||||
; Pages
|
||||
|
||||
Page directory
|
||||
Page instfiles
|
||||
|
||||
;--------------------------------
|
||||
|
||||
; The stuff to install
|
||||
Section "" ;No components page, name is not important
|
||||
|
||||
; Set output path to the installation directory.
|
||||
SetOutPath $INSTDIR
|
||||
|
||||
; Put file there
|
||||
File ..\Release\newcoin.exe
|
||||
File ..\*.dll
|
||||
File "start CoinToss.bat"
|
||||
File newcoind.cfg
|
||||
File validators.txt
|
||||
File /r /x .git ..\..\nc-client\*.*
|
||||
|
||||
|
||||
|
||||
SectionEnd ; end the section
|
||||
149
deploy/newcoind.cfg
Normal file
149
deploy/newcoind.cfg
Normal file
@@ -0,0 +1,149 @@
|
||||
#
|
||||
# Sample newcoind.cfg
|
||||
#
|
||||
# This file should be named newcoind.cfg. This file is UTF-8 with Dos, UNIX,
|
||||
# or Mac style end of lines. Blank lines and lines beginning with '#' are
|
||||
# ignored. Undefined sections are reserved. No escapes are currently defined.
|
||||
#
|
||||
# When you launch newcoind, it will attempt to find this file.
|
||||
#
|
||||
# --conf=<path>:
|
||||
# You may specify the location of this file with --conf=<path>. The config
|
||||
# directory is the directory containing this file. The data directory is a
|
||||
# the subdirectory named "dbs".
|
||||
#
|
||||
# Windows and no --conf:
|
||||
# The config directory is the same directory as the newcoind program. The
|
||||
# data directory is a the subdirectory named "dbs".
|
||||
#
|
||||
# Other OSes and no --conf:
|
||||
# This file will be looked for in these places in the following order:
|
||||
# ./newcoind.cfg
|
||||
# $XDG_CONFIG_HOME/newcoin/newcoind.cfg
|
||||
#
|
||||
# If newcoind.cfg, is found in the current working directory, the directory
|
||||
# will be used as the config directory. The data directory is a the
|
||||
# subdirectory named "dbs".
|
||||
#
|
||||
# Otherwise, the data directory data is:
|
||||
# $XDG_DATA_HOME/newcoin/
|
||||
#
|
||||
# Note: $XDG_CONFIG_HOME defaults to $HOME/.config
|
||||
# $XDG_DATA_HOME defaults to $HOME/.local/share
|
||||
#
|
||||
# [debug_logfile]
|
||||
# Specifies were a debug logfile is kept. By default, no debug log is kept
|
||||
#
|
||||
# Example: debug.log
|
||||
#
|
||||
# [validators_site]:
|
||||
# Specifies where to find validators.txt for UNL boostrapping and RPC command unl_network.
|
||||
# During alpha testing, this defaults to: redstem.com
|
||||
#
|
||||
# Example: newcoin.org
|
||||
#
|
||||
# [unl_default]:
|
||||
# XXX This should be called: [validators_file]
|
||||
# Specifies how to bootstrap the UNL list. The UNL list is based on a
|
||||
# validators.txt file and is maintained in the databases. When newcoind
|
||||
# starts up, if the databases are missing or are obsolete due to an upgrade
|
||||
# of newcoind, newcoind will reconstruct the UNL list as specified here.
|
||||
#
|
||||
# If this entry is not present or empty, newcoind will look for a validators.txt in the
|
||||
# config directory. If not found there, it will attempt to retrieve the file
|
||||
# from the newcoin foundation's web site.
|
||||
#
|
||||
# This entry is also used by the RPC command unl_load.
|
||||
#
|
||||
# Specify the file by specifying its full path.
|
||||
#
|
||||
# Examples:
|
||||
# C:/home/johndoe/newcoin/validators.txt
|
||||
# /home/johndoe/newcoin/validators.txt
|
||||
#
|
||||
# [validators]:
|
||||
# Only valid in "newcoind.cfg", "newcoin.txt", and the referered [validators_url].
|
||||
# List of nodes to accept as validators speficied by public key or domain.
|
||||
#
|
||||
# For domains, newcoind will probe for https web servers at the specied
|
||||
# domain in the following order: newcoin.DOMAIN, www.DOMAIN, DOMAIN
|
||||
#
|
||||
# Examples:
|
||||
# redstem.com
|
||||
# n9KorY8QtTdRx7TVDpwnG9NvyxsDwHUKUEeDLY3AkiGncVaSXZi5
|
||||
# n9MqiExBcoG19UXwoLjBJnhsxEhAZMuWwJDRdkyDz1EkEkwzQTNt John Doe
|
||||
#
|
||||
# [ips]:
|
||||
# Only valid in "newcoind.cfg", "newcoin.txt", and the referered [ips_url].
|
||||
# List of ips where the Newcoin protocol is avialable.
|
||||
# One ipv4 or ipv6 address per line.
|
||||
# A port may optionally be specified after adding a space to the address.
|
||||
# By convention, if known, IPs are listed in from most to least trusted.
|
||||
#
|
||||
# Examples:
|
||||
# 192.168.0.1
|
||||
# 192.168.0.1 3939
|
||||
# 2001:0db8:0100:f101:0210:a4ff:fee3:9566
|
||||
#
|
||||
# [peer_ip]:
|
||||
# IP address or domain to bind to allow external connections from peers.
|
||||
# Defaults to not allow external connections from peers.
|
||||
#
|
||||
# Examples: 0.0.0.0 - Bind on all interfaces.
|
||||
#
|
||||
# [peer_port]:
|
||||
# Port to bind to allow external connections from peers.
|
||||
#
|
||||
# [rpc_ip]:
|
||||
# IP address or domain to bind to allow insecure RPC connections.
|
||||
# Defaults to not allow RPC connections.
|
||||
#
|
||||
# [rpc_port]:
|
||||
# Port to bind to if allowing insecure RPC connections.
|
||||
#
|
||||
# [rpc_allow_remote]:
|
||||
# 0 or 1. 0 only allows RPC connections from 127.0.0.1. [default 0]
|
||||
#
|
||||
# [websocket_ip]:
|
||||
# IP address or domain to bind to allow client connections.
|
||||
#
|
||||
# Examples: 0.0.0.0 - Bind on all interfaces.
|
||||
# 127.0.0.1 - Bind on localhost interface. Only local programs may connect.
|
||||
#
|
||||
# [websocket_port]:
|
||||
# Port to bind to allow client connections.
|
||||
#
|
||||
# [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 validation_create command.
|
||||
#
|
||||
# Examples: RASH BUSH MILK LOOK BAD BRIM AVID GAFF BAIT ROT POD LOVE
|
||||
# shfArahZT9Q9ckTf3s1psJ7C7qzVN
|
||||
#
|
||||
|
||||
[peer_ip]
|
||||
0.0.0.0
|
||||
|
||||
[peer_port]
|
||||
51235
|
||||
|
||||
[rpc_ip]
|
||||
127.0.0.1
|
||||
|
||||
[rpc_port]
|
||||
5005
|
||||
|
||||
[rpc_allow_remote]
|
||||
1
|
||||
|
||||
[debug_logfile]
|
||||
debug.log
|
||||
|
||||
[unl_default]
|
||||
validators.txt
|
||||
|
||||
[ips]
|
||||
23.21.167.100 51235
|
||||
23.23.201.55 51235
|
||||
107.21.116.214 51235
|
||||
3
deploy/start CoinToss.bat
Normal file
3
deploy/start CoinToss.bat
Normal file
@@ -0,0 +1,3 @@
|
||||
start newcoin
|
||||
sleep 4
|
||||
start index.html
|
||||
26
deploy/validators.txt
Normal file
26
deploy/validators.txt
Normal file
@@ -0,0 +1,26 @@
|
||||
#
|
||||
# Default validators.txt
|
||||
#
|
||||
# A list of domains to bootstrap a nodes UNLs or for clients to indirectly
|
||||
# locate IPs to contact the Newcoin network.
|
||||
#
|
||||
# This file is UTF-8 with Dos, UNIX, or Mac style end of lines.
|
||||
# Blank lines and lines starting with a '#' are ignored.
|
||||
# All other lines should be hankos or domain names.
|
||||
#
|
||||
# [validators]:
|
||||
# List of nodes to accept as validators specified by public key or domain.
|
||||
#
|
||||
# For domains, newcoind will probe for https web servers at the specified
|
||||
# domain in the following order: newcoin.DOMAIN, www.DOMAIN, DOMAIN
|
||||
#
|
||||
# Examples: redstem.com
|
||||
# n9KorY8QtTdRx7TVDpwnG9NvyxsDwHUKUEeDLY3AkiGncVaSXZi5
|
||||
# n9MqiExBcoG19UXwoLjBJnhsxEhAZMuWwJDRdkyDz1EkEkwzQTNt John Doe
|
||||
#
|
||||
|
||||
[validators]
|
||||
n9LQC4xFSWXNv1SU1sKtjrW6TZpBZSwp1nRWej8saGs155x42YFZ first
|
||||
n9LFzWuhKNvXStHAuemfRKFVECLApowncMAM5chSCL9R5ECHGN4V second
|
||||
n9KXAZxiHkWuVGxDEE8boW7WmcycpZNmWei4vxVaywLZ391Nbuqx third
|
||||
n94365hzFKikgCULeJwczs3kwzpir3KVHkfhUWGT4MjmbEbC5xBy
|
||||
12
newcoin.txt
12
newcoin.txt
@@ -31,7 +31,7 @@
|
||||
# Example: google.com
|
||||
#
|
||||
# [ips]:
|
||||
# Only valid in "newcoin.txt" and the referered [ips_url].
|
||||
# Only valid in "newcoind.cfg", "newcoin.txt", and the referered [ips_url].
|
||||
# List of ips where the Newcoin protocol is avialable.
|
||||
# One ipv4 or ipv6 address per line.
|
||||
# A port may optionally be specified after adding a space to the address.
|
||||
@@ -43,12 +43,16 @@
|
||||
# 2001:0db8:0100:f101:0210:a4ff:fee3:9566
|
||||
#
|
||||
# [validators]:
|
||||
# Only valid in "newcoin.txt" and the referered [validators_url].
|
||||
# Only valid in "newcoind.cfg", "newcoin.txt", and the referered [validators_url].
|
||||
# List of Newcoin validators this node recommends.
|
||||
#
|
||||
# For domains, newcoind will probe for https web servers at the specied
|
||||
# domain in the following order: newcoin.DOMAIN, www.DOMAIN, DOMAIN
|
||||
#
|
||||
# Examples:
|
||||
# amazon.com
|
||||
# newegg.com
|
||||
# redstem.com
|
||||
# n9KorY8QtTdRx7TVDpwnG9NvyxsDwHUKUEeDLY3AkiGncVaSXZi5
|
||||
# n9MqiExBcoG19UXwoLjBJnhsxEhAZMuWwJDRdkyDz1EkEkwzQTNt John Doe
|
||||
#
|
||||
# [ips_url]:
|
||||
# Only valid in "newcoin.txt".
|
||||
|
||||
@@ -72,7 +72,7 @@
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>BOOST_TEST_NO_MAIN;_CRT_SECURE_NO_WARNINGS;_WIN32_WINNT=0x0501;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>BOOST_TEST_ALTERNATIVE_INIT_API;BOOST_TEST_NO_MAIN;_CRT_SECURE_NO_WARNINGS;_WIN32_WINNT=0x0501;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>..\OpenSSL\include;..\boost_1_47_0;..\protobuf-2.4.1\src</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
@@ -144,12 +144,14 @@
|
||||
<ClCompile Include="src\SHAMapDiff.cpp" />
|
||||
<ClCompile Include="src\SHAMapNodes.cpp" />
|
||||
<ClCompile Include="src\SHAMapSync.cpp" />
|
||||
<ClCompile Include="src\Suppression.cpp" />
|
||||
<ClCompile Include="src\Transaction.cpp" />
|
||||
<ClCompile Include="src\TransactionEngine.cpp" />
|
||||
<ClCompile Include="src\TransactionFormats.cpp" />
|
||||
<ClCompile Include="src\TransactionMaster.cpp" />
|
||||
<ClCompile Include="src\UniqueNodeList.cpp" />
|
||||
<ClCompile Include="src\utils.cpp" />
|
||||
<ClCompile Include="src\ValidationCollection.cpp" />
|
||||
<ClCompile Include="src\Wallet.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
||||
@@ -237,6 +237,12 @@
|
||||
<ClCompile Include="src\CanonicalTXSet.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\ValidationCollection.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\Suppression.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="KnownNodeList.h">
|
||||
|
||||
40
newcoind.cfg
40
newcoind.cfg
@@ -31,6 +31,11 @@
|
||||
# Note: $XDG_CONFIG_HOME defaults to $HOME/.config
|
||||
# $XDG_DATA_HOME defaults to $HOME/.local/share
|
||||
#
|
||||
# [debug_logfile]
|
||||
# Specifies were a debug logfile is kept. By default, no debug log is kept
|
||||
#
|
||||
# Example: debug.log
|
||||
#
|
||||
# [validators_site]:
|
||||
# Specifies where to find validators.txt for UNL boostrapping and RPC command unl_network.
|
||||
# During alpha testing, this defaults to: redstem.com
|
||||
@@ -52,18 +57,33 @@
|
||||
#
|
||||
# Specify the file by specifying its full path.
|
||||
#
|
||||
# Examples: C:/home/johndoe/newcoin/validators.txt
|
||||
# /home/johndoe/newcoin/validators.txt
|
||||
# Examples:
|
||||
# C:/home/johndoe/newcoin/validators.txt
|
||||
# /home/johndoe/newcoin/validators.txt
|
||||
#
|
||||
# [validators]:
|
||||
# Only valid in "newcoind.cfg", "newcoin.txt", and the referered [validators_url].
|
||||
# List of nodes to accept as validators speficied by public key or domain.
|
||||
#
|
||||
# For domains, newcoind will probe for https web servers at the specied
|
||||
# domain in the following order: newcoin.DOMAIN, www.DOMAIN, DOMAIN
|
||||
#
|
||||
# Examples: redstem.com
|
||||
# n9KorY8QtTdRx7TVDpwnG9NvyxsDwHUKUEeDLY3AkiGncVaSXZi5
|
||||
# n9MqiExBcoG19UXwoLjBJnhsxEhAZMuWwJDRdkyDz1EkEkwzQTNt John Doe
|
||||
# Examples:
|
||||
# redstem.com
|
||||
# n9KorY8QtTdRx7TVDpwnG9NvyxsDwHUKUEeDLY3AkiGncVaSXZi5
|
||||
# n9MqiExBcoG19UXwoLjBJnhsxEhAZMuWwJDRdkyDz1EkEkwzQTNt John Doe
|
||||
#
|
||||
# [ips]:
|
||||
# Only valid in "newcoind.cfg", "newcoin.txt", and the referered [ips_url].
|
||||
# List of ips where the Newcoin protocol is avialable.
|
||||
# One ipv4 or ipv6 address per line.
|
||||
# A port may optionally be specified after adding a space to the address.
|
||||
# By convention, if known, IPs are listed in from most to least trusted.
|
||||
#
|
||||
# Examples:
|
||||
# 192.168.0.1
|
||||
# 192.168.0.1 3939
|
||||
# 2001:0db8:0100:f101:0210:a4ff:fee3:9566
|
||||
#
|
||||
# [peer_ip]:
|
||||
# IP address or domain to bind to allow external connections from peers.
|
||||
@@ -117,8 +137,16 @@
|
||||
[rpc_allow_remote]
|
||||
1
|
||||
|
||||
[debug_logfile]
|
||||
debug.log
|
||||
|
||||
[validation_seed]
|
||||
snTBDmrhUK3znvF8AaQURLm4UCkbS
|
||||
shh1D4oj5czH3PUEjYES8c7Bay3tE
|
||||
|
||||
[unl_default]
|
||||
validators.txt
|
||||
|
||||
[ips]
|
||||
23.21.167.100 51235
|
||||
23.23.201.55 51235
|
||||
107.21.116.214 51235
|
||||
|
||||
@@ -100,7 +100,7 @@ bool STAmount::setValue(const std::string& sAmount, const std::string& sCurrency
|
||||
|
||||
if (bInteger)
|
||||
{
|
||||
uValue = sAmount.empty() ? 0 : boost::lexical_cast<unsigned int>(sAmount);
|
||||
uValue = sAmount.empty() ? 0 : boost::lexical_cast<uint64>(sAmount);
|
||||
iOffset = 0;
|
||||
}
|
||||
else
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <boost/thread.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
|
||||
#include "../database/SqliteDatabase.h"
|
||||
|
||||
#include "Application.h"
|
||||
@@ -12,6 +15,7 @@
|
||||
#include "utils.h"
|
||||
#include "TaggedCache.h"
|
||||
#include "boost/filesystem.hpp"
|
||||
#include "Log.h"
|
||||
|
||||
Application* theApp = NULL;
|
||||
|
||||
@@ -51,18 +55,26 @@ void Application::stop()
|
||||
std::cerr << "Stopped: " << mIOService.stopped() << std::endl;
|
||||
}
|
||||
|
||||
static void InitDB(DatabaseCon** dbCon, const char *fileName, const char *dbInit[], int dbCount)
|
||||
{
|
||||
*dbCon = new DatabaseCon(fileName, dbInit, dbCount);
|
||||
}
|
||||
|
||||
void Application::run()
|
||||
{
|
||||
assert(mTxnDB==NULL);
|
||||
assert(mTxnDB == NULL);
|
||||
if (!theConfig.DEBUG_LOGFILE.empty())
|
||||
Log::setLogFile(theConfig.DEBUG_LOGFILE);
|
||||
|
||||
//
|
||||
// Construct databases.
|
||||
//
|
||||
mTxnDB = new DatabaseCon("transaction.db", TxnDBInit, TxnDBCount);
|
||||
mLedgerDB = new DatabaseCon("ledger.db", LedgerDBInit, LedgerDBCount);
|
||||
mWalletDB = new DatabaseCon("wallet.db", WalletDBInit, WalletDBCount);
|
||||
mHashNodeDB = new DatabaseCon("hashnode.db", HashNodeDBInit, HashNodeDBCount);
|
||||
mNetNodeDB = new DatabaseCon("netnode.db", NetNodeDBInit, NetNodeDBCount);
|
||||
boost::thread t1(boost::bind(&InitDB, &mTxnDB, "transaction.db", TxnDBInit, TxnDBCount));
|
||||
boost::thread t2(boost::bind(&InitDB, &mLedgerDB, "ledger.db", LedgerDBInit, LedgerDBCount));
|
||||
boost::thread t3(boost::bind(&InitDB, &mWalletDB, "wallet.db", WalletDBInit, WalletDBCount));
|
||||
boost::thread t4(boost::bind(&InitDB, &mHashNodeDB, "hashnode.db", HashNodeDBInit, HashNodeDBCount));
|
||||
boost::thread t5(boost::bind(&InitDB, &mNetNodeDB, "netnode.db", NetNodeDBInit, NetNodeDBCount));
|
||||
t1.join(); t2.join(); t3.join(); t4.join(); t5.join();
|
||||
|
||||
//
|
||||
// Begin validation and ip maintenance.
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include "NetworkOPs.h"
|
||||
#include "TaggedCache.h"
|
||||
#include "ValidationCollection.h"
|
||||
#include "Suppression.h"
|
||||
#include "../database/database.h"
|
||||
|
||||
|
||||
@@ -46,6 +47,7 @@ class Application
|
||||
NetworkOPs mNetOps;
|
||||
NodeCache mNodeCache;
|
||||
ValidationCollection mValidations;
|
||||
SuppressionTable mSuppressions;
|
||||
|
||||
DatabaseCon *mTxnDB, *mLedgerDB, *mWalletDB, *mHashNodeDB, *mNetNodeDB;
|
||||
|
||||
@@ -77,6 +79,8 @@ public:
|
||||
TransactionMaster& getMasterTransaction() { return mMasterTransaction; }
|
||||
NodeCache& getNodeCache() { return mNodeCache; }
|
||||
ValidationCollection& getValidations() { return mValidations; }
|
||||
bool suppress(const uint256& s) { return mSuppressions.addSuppression(s); }
|
||||
bool suppress(const uint160& s) { return mSuppressions.addSuppression(s); }
|
||||
|
||||
DatabaseCon* getTxnDB() { return mTxnDB; }
|
||||
DatabaseCon* getLedgerDB() { return mLedgerDB; }
|
||||
|
||||
@@ -44,10 +44,12 @@ void CanonicalTXSet::push_back(SerializedTransaction::pointer txn)
|
||||
mMap.insert(std::make_pair(CanonicalTXKey(effectiveAccount, txn->getSequence(), txn->getTransactionID()), txn));
|
||||
}
|
||||
|
||||
void CanonicalTXSet::eraseInc(iterator& it)
|
||||
CanonicalTXSet::iterator CanonicalTXSet::erase(const iterator& it)
|
||||
{
|
||||
iterator tmp = it++;
|
||||
mMap.erase(tmp);
|
||||
iterator tmp = it;
|
||||
++tmp;
|
||||
mMap.erase(it);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -39,8 +39,7 @@ public:
|
||||
CanonicalTXSet(const uint256& lclHash) : mSetHash(lclHash) { ; }
|
||||
|
||||
void push_back(SerializedTransaction::pointer txn);
|
||||
void erase(const iterator& it) { mMap.erase(it); }
|
||||
void eraseInc(iterator& it);
|
||||
iterator erase(const iterator& it);
|
||||
|
||||
iterator begin() { return mMap.begin(); }
|
||||
iterator end() { return mMap.end(); }
|
||||
|
||||
@@ -7,9 +7,11 @@
|
||||
#include <iostream>
|
||||
|
||||
#define SECTION_ACCOUNT_PROBE_MAX "account_probe_max"
|
||||
#define SECTION_DEBUG_LOGFILE "debug_logfile"
|
||||
#define SECTION_FEE_ACCOUNT_CREATE "fee_account_create"
|
||||
#define SECTION_FEE_DEFAULT "fee_default"
|
||||
#define SECTION_FEE_NICKNAME_CREATE "fee_nickname_create"
|
||||
#define SECTION_IPS "ips"
|
||||
#define SECTION_NETWORK_QUORUM "network_quorum"
|
||||
#define SECTION_PEER_CONNECT_LOW_WATER "peer_connect_low_water"
|
||||
#define SECTION_PEER_IP "peer_ip"
|
||||
@@ -172,13 +174,21 @@ void Config::load()
|
||||
section secConfig = ParseSection(strConfigFile, true);
|
||||
std::string strTemp;
|
||||
|
||||
// XXX Leak
|
||||
section::mapped_type* smtTmp;
|
||||
|
||||
smtTmp = sectionEntries(secConfig, SECTION_VALIDATORS);
|
||||
if (smtTmp)
|
||||
{
|
||||
VALIDATORS = *smtTmp;
|
||||
sectionEntriesPrint(&VALIDATORS, SECTION_VALIDATORS);
|
||||
// sectionEntriesPrint(&VALIDATORS, SECTION_VALIDATORS);
|
||||
}
|
||||
|
||||
smtTmp = sectionEntries(secConfig, SECTION_IPS);
|
||||
if (smtTmp)
|
||||
{
|
||||
IPS = *smtTmp;
|
||||
sectionEntriesPrint(&IPS, SECTION_IPS);
|
||||
}
|
||||
|
||||
(void) sectionSingleB(secConfig, SECTION_VALIDATORS_SITE, VALIDATORS_SITE);
|
||||
@@ -205,7 +215,9 @@ void Config::load()
|
||||
VALIDATION_SEED.setSeedGeneric(strTemp);
|
||||
|
||||
(void) sectionSingleB(secConfig, SECTION_PEER_SSL_CIPHER_LIST, PEER_SSL_CIPHER_LIST);
|
||||
|
||||
if (sectionSingleB(secConfig, SECTION_PEER_SCAN_INTERVAL_MIN, strTemp))
|
||||
// Minimum for min is 60 seconds.
|
||||
PEER_SCAN_INTERVAL_MIN = MAX(60, boost::lexical_cast<int>(strTemp));
|
||||
|
||||
if (sectionSingleB(secConfig, SECTION_PEER_START_MAX, strTemp))
|
||||
@@ -234,6 +246,9 @@ void Config::load()
|
||||
|
||||
if (sectionSingleB(secConfig, SECTION_UNL_DEFAULT, strTemp))
|
||||
UNL_DEFAULT = strTemp;
|
||||
|
||||
if (sectionSingleB(secConfig, SECTION_DEBUG_LOGFILE, strTemp))
|
||||
DEBUG_LOGFILE = strTemp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
12
src/Config.h
12
src/Config.h
@@ -29,8 +29,10 @@ const int SYSTEM_WEBSOCKET_PORT = 6562;
|
||||
// Allow anonymous DH.
|
||||
#define DEFAULT_PEER_SSL_CIPHER_LIST "ALL:!LOW:!EXP:!MD5:@STRENGTH"
|
||||
|
||||
// 1 hour.
|
||||
#define DEFAULT_PEER_SCAN_INTERVAL_MIN (60*60)
|
||||
// Normal, recommend 1 hour.
|
||||
// #define DEFAULT_PEER_SCAN_INTERVAL_MIN (60*60)
|
||||
// Testing, recommend 1 minute.
|
||||
#define DEFAULT_PEER_SCAN_INTERVAL_MIN (60)
|
||||
|
||||
// Maximum number of peers to try to connect to as client at once.
|
||||
#define DEFAULT_PEER_START_MAX 5
|
||||
@@ -49,13 +51,15 @@ public:
|
||||
boost::filesystem::path CONFIG_FILE;
|
||||
boost::filesystem::path CONFIG_DIR;
|
||||
boost::filesystem::path DATA_DIR;
|
||||
boost::filesystem::path DEBUG_LOGFILE;
|
||||
boost::filesystem::path UNL_DEFAULT;
|
||||
|
||||
std::string VALIDATORS_SITE; // Where to find validators.txt on the Internet.
|
||||
std::vector<std::string> VALIDATORS; // Validators from newcoind.cfg
|
||||
std::vector<std::string> VALIDATORS; // Validators from newcoind.cfg.
|
||||
std::vector<std::string> IPS; // Peer IPs from newcoind.cfg.
|
||||
|
||||
// Network parameters
|
||||
int NETWORK_START_TIME; // The Unix time we start ledger 0
|
||||
int NETWORK_START_TIME; // The Unix time we start ledger 0.
|
||||
int TRANSACTION_FEE_BASE;
|
||||
int LEDGER_SECONDS;
|
||||
int LEDGER_PROPOSAL_DELAY_SECONDS;
|
||||
|
||||
@@ -1,9 +1,5 @@
|
||||
|
||||
#include "ConnectionPool.h"
|
||||
#include "Config.h"
|
||||
#include "Peer.h"
|
||||
#include "Application.h"
|
||||
#include "utils.h"
|
||||
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
@@ -11,6 +7,13 @@
|
||||
#include <boost/format.hpp>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
|
||||
#include "Config.h"
|
||||
#include "Peer.h"
|
||||
#include "Application.h"
|
||||
#include "utils.h"
|
||||
#include "Log.h"
|
||||
|
||||
|
||||
// How often to enforce policies.
|
||||
#define POLICY_INTERVAL_SECONDS 5
|
||||
|
||||
@@ -25,7 +28,6 @@ void splitIpPort(const std::string& strIpPort, std::string& strIp, int& iPort)
|
||||
|
||||
ConnectionPool::ConnectionPool(boost::asio::io_service& io_service) :
|
||||
mCtx(boost::asio::ssl::context::sslv23),
|
||||
bScanning(false),
|
||||
mScanTimer(io_service),
|
||||
mPolicyTimer(io_service)
|
||||
{
|
||||
@@ -49,42 +51,62 @@ void ConnectionPool::start()
|
||||
|
||||
bool ConnectionPool::getTopNAddrs(int n,std::vector<std::string>& addrs)
|
||||
{
|
||||
Database* db = theApp->getWalletDB()->getDB();
|
||||
// XXX Filter out other local addresses (like ipv6)
|
||||
Database* db = theApp->getWalletDB()->getDB();
|
||||
ScopedLock sl(theApp->getWalletDB()->getDBLock());
|
||||
SQL_FOREACH(db, str(boost::format("SELECT IpPort FROM PeerIps limit %d") % n) )
|
||||
|
||||
SQL_FOREACH(db, str(boost::format("SELECT IpPort FROM PeerIps LIMIT %d") % n) )
|
||||
{
|
||||
std::string str;
|
||||
|
||||
db->getStr(0,str);
|
||||
|
||||
addrs.push_back(str);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ConnectionPool::savePeer(const std::string& strIp, int iPort,char code)
|
||||
bool ConnectionPool::savePeer(const std::string& strIp, int iPort, char code)
|
||||
{
|
||||
bool bNew = false;
|
||||
|
||||
Database* db = theApp->getWalletDB()->getDB();
|
||||
|
||||
std::string ipPort=db->escape(str(boost::format("%s %d") % strIp % iPort));
|
||||
std::string ipPort = sqlEscape(str(boost::format("%s %d") % strIp % iPort));
|
||||
|
||||
ScopedLock sl(theApp->getWalletDB()->getDBLock());
|
||||
std::string sql=str(boost::format("SELECT count(*) FROM PeerIps WHERE IpPort=%s;") % ipPort);
|
||||
std::string sql = str(boost::format("SELECT COUNT(*) FROM PeerIps WHERE IpPort=%s;") % ipPort);
|
||||
if (db->executeSQL(sql) && db->startIterRows())
|
||||
{
|
||||
if ( db->getInt(0)==0)
|
||||
if (!db->getInt(0))
|
||||
{
|
||||
db->executeSQL(str(boost::format("INSERT INTO PeerIps (IpPort,Score,Source) values (%s,0,'%c');") % ipPort % code));
|
||||
return true;
|
||||
}// else we already had this peer
|
||||
db->executeSQL(str(boost::format("INSERT INTO PeerIps (IpPort,Score,Source) values (%s,0,'%c');") % ipPort % code));
|
||||
bNew = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// We already had this peer.
|
||||
// We will eventually verify its address if it is possible.
|
||||
// YYY If it is vsInbound, then we might make verification immediate so we can connect back sooner if the connection
|
||||
// is lost.
|
||||
nothing();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "Error saving Peer" << std::endl;
|
||||
}
|
||||
|
||||
return false;
|
||||
if (bNew)
|
||||
scanRefresh();
|
||||
|
||||
return bNew;
|
||||
}
|
||||
|
||||
// An available peer is one we had no trouble connect to last time and that we are not currently knowingly connected or connecting
|
||||
// too.
|
||||
//
|
||||
// <-- true, if a peer is available to connect to
|
||||
bool ConnectionPool::peerAvailable(std::string& strIp, int& iPort)
|
||||
{
|
||||
@@ -94,6 +116,7 @@ bool ConnectionPool::peerAvailable(std::string& strIp, int& iPort)
|
||||
// Convert mIpMap (list of open connections) to a vector of "<ip> <port>".
|
||||
{
|
||||
boost::mutex::scoped_lock sl(mPeerLock);
|
||||
|
||||
vstrIpPort.reserve(mIpMap.size());
|
||||
|
||||
BOOST_FOREACH(pipPeer ipPeer, mIpMap)
|
||||
@@ -101,19 +124,22 @@ bool ConnectionPool::peerAvailable(std::string& strIp, int& iPort)
|
||||
const std::string& strIp = ipPeer.first.first;
|
||||
int iPort = ipPeer.first.second;
|
||||
|
||||
vstrIpPort.push_back(db->escape(str(boost::format("%s %d") % strIp % iPort)));
|
||||
vstrIpPort.push_back(sqlEscape(str(boost::format("%s %d") % strIp % iPort)));
|
||||
}
|
||||
}
|
||||
|
||||
// Get the first IpPort entry which is not in vector and which is not scheduled for scanning.
|
||||
std::string strIpPort;
|
||||
|
||||
ScopedLock sl(theApp->getWalletDB()->getDBLock());
|
||||
if (db->executeSQL(str(boost::format("SELECT IpPort FROM PeerIps WHERE ScanNext IS NULL AND IpPort NOT IN (%s) LIMIT 1;")
|
||||
% strJoin(vstrIpPort.begin(), vstrIpPort.end(), ",")))
|
||||
&& db->startIterRows())
|
||||
{
|
||||
db->getStr("IpPort", strIpPort);
|
||||
ScopedLock sl(theApp->getWalletDB()->getDBLock());
|
||||
|
||||
if (db->executeSQL(str(boost::format("SELECT IpPort FROM PeerIps WHERE ScanNext IS NULL AND IpPort NOT IN (%s) LIMIT 1;")
|
||||
% strJoin(vstrIpPort.begin(), vstrIpPort.end(), ",")))
|
||||
&& db->startIterRows())
|
||||
{
|
||||
strIpPort = db->getStrBinary("IpPort");
|
||||
}
|
||||
}
|
||||
|
||||
bool bAvailable = !strIpPort.empty();
|
||||
@@ -124,6 +150,7 @@ bool ConnectionPool::peerAvailable(std::string& strIp, int& iPort)
|
||||
return bAvailable;
|
||||
}
|
||||
|
||||
// Make sure we have at least low water connections.
|
||||
void ConnectionPool::policyLowWater()
|
||||
{
|
||||
std::string strIp;
|
||||
@@ -133,6 +160,8 @@ void ConnectionPool::policyLowWater()
|
||||
if (mConnectedMap.size() > theConfig.PEER_CONNECT_LOW_WATER)
|
||||
{
|
||||
// Above low water mark, don't need more connections.
|
||||
Log(lsTRACE) << "Pool: Low water: sufficient connections: " << mConnectedMap.size() << "/" << theConfig.PEER_CONNECT_LOW_WATER;
|
||||
|
||||
nothing();
|
||||
}
|
||||
#if 0
|
||||
@@ -145,14 +174,18 @@ void ConnectionPool::policyLowWater()
|
||||
else if (!peerAvailable(strIp, iPort))
|
||||
{
|
||||
// No more connections available to start.
|
||||
Log(lsTRACE) << "Pool: Low water: no peers available.";
|
||||
|
||||
// XXX Might ask peers for more ips.
|
||||
nothing();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Try to start connection.
|
||||
if (!connectTo(strIp, iPort))
|
||||
throw std::runtime_error("Internal error: standby was already connected.");
|
||||
Log(lsTRACE) << "Pool: Low water: start connection.";
|
||||
|
||||
if (!peerConnect(strIp, iPort))
|
||||
Log(lsINFO) << "Pool: Low water: already connected.";
|
||||
|
||||
// Check if we need more.
|
||||
policyLowWater();
|
||||
@@ -161,24 +194,14 @@ void ConnectionPool::policyLowWater()
|
||||
|
||||
void ConnectionPool::policyEnforce()
|
||||
{
|
||||
boost::posix_time::ptime tpNow = boost::posix_time::second_clock::universal_time();
|
||||
|
||||
std::cerr << "policyEnforce: begin: " << tpNow << std::endl;
|
||||
|
||||
// Cancel any in progrss timer.
|
||||
// Cancel any in progress timer.
|
||||
(void) mPolicyTimer.cancel();
|
||||
|
||||
// Enforce policies.
|
||||
policyLowWater();
|
||||
|
||||
// Schedule next enforcement.
|
||||
boost::posix_time::ptime tpNext;
|
||||
|
||||
tpNext = boost::posix_time::second_clock::universal_time()+boost::posix_time::seconds(POLICY_INTERVAL_SECONDS);
|
||||
|
||||
std::cerr << "policyEnforce: schedule : " << tpNext << std::endl;
|
||||
|
||||
mPolicyTimer.expires_at(tpNext);
|
||||
mPolicyTimer.expires_at(boost::posix_time::second_clock::universal_time()+boost::posix_time::seconds(POLICY_INTERVAL_SECONDS));
|
||||
mPolicyTimer.async_wait(boost::bind(&ConnectionPool::policyHandler, this, _1));
|
||||
}
|
||||
|
||||
@@ -198,7 +221,8 @@ void ConnectionPool::policyHandler(const boost::system::error_code& ecResult)
|
||||
}
|
||||
}
|
||||
|
||||
// XXX Broken: also don't send a message to a peer if we got it from the peer.
|
||||
// YYY: Should probably do this in the background.
|
||||
// YYY: Might end up sending to disconnected peer?
|
||||
void ConnectionPool::relayMessage(Peer* fromPeer, PackedMessage::pointer msg)
|
||||
{
|
||||
boost::mutex::scoped_lock sl(mPeerLock);
|
||||
@@ -208,83 +232,76 @@ void ConnectionPool::relayMessage(Peer* fromPeer, PackedMessage::pointer msg)
|
||||
Peer::pointer peer = pair.second;
|
||||
if (!peer)
|
||||
std::cerr << "CP::RM null peer in list" << std::endl;
|
||||
else if (!fromPeer || !(peer.get() == fromPeer))
|
||||
else if ((!fromPeer || !(peer.get() == fromPeer)) && peer->isConnected())
|
||||
peer->sendPacket(msg);
|
||||
}
|
||||
}
|
||||
|
||||
// Inbound connection, false=reject
|
||||
// Reject addresses we already have in our table.
|
||||
// XXX Reject, if we have too many connections.
|
||||
bool ConnectionPool::peerRegister(Peer::pointer peer, const std::string& strIp, int iPort)
|
||||
// Schedule a connection via scanning.
|
||||
//
|
||||
// Add or modify into PeerIps as a manual entry for immediate scanning.
|
||||
// Requires sane IP and port.
|
||||
void ConnectionPool::connectTo(const std::string& strIp, int iPort)
|
||||
{
|
||||
bool bAccept;
|
||||
ipPort ip = make_pair(strIp, iPort);
|
||||
{
|
||||
Database* db = theApp->getWalletDB()->getDB();
|
||||
ScopedLock sl(theApp->getWalletDB()->getDBLock());
|
||||
|
||||
db->executeSQL(str(boost::format("REPLACE INTO PeerIps (IpPort,Score,Source,ScanNext) values (%s,%d,'%c',0);")
|
||||
% sqlEscape(str(boost::format("%s %d") % strIp % iPort))
|
||||
% theApp->getUNL().iSourceScore(UniqueNodeList::vsManual)
|
||||
% char(UniqueNodeList::vsManual)));
|
||||
}
|
||||
|
||||
scanRefresh();
|
||||
}
|
||||
|
||||
// Start a connection, if not already known connected or connecting.
|
||||
//
|
||||
// <-- true, if already connected.
|
||||
Peer::pointer ConnectionPool::peerConnect(const std::string& strIp, int iPort)
|
||||
{
|
||||
ipPort pipPeer = make_pair(strIp, iPort);
|
||||
Peer::pointer ppResult = Peer::pointer();
|
||||
|
||||
boost::unordered_map<ipPort, Peer::pointer>::iterator it;
|
||||
|
||||
boost::mutex::scoped_lock sl(mPeerLock);
|
||||
|
||||
it = mIpMap.find(ip);
|
||||
|
||||
if (it == mIpMap.end())
|
||||
{
|
||||
// Did not find it. Not already connecting or connected.
|
||||
boost::mutex::scoped_lock sl(mPeerLock);
|
||||
|
||||
std::cerr << "ConnectionPool::peerRegister: " << ip.first << " " << ip.second << std::endl;
|
||||
// Mark as connecting.
|
||||
mIpMap[ip] = peer;
|
||||
bAccept = true;
|
||||
if ((it = mIpMap.find(pipPeer)) == mIpMap.end())
|
||||
{
|
||||
Peer::pointer ppNew(Peer::create(theApp->getIOService(), mCtx));
|
||||
|
||||
// Did not find it. Not already connecting or connected.
|
||||
ppNew->connect(strIp, iPort);
|
||||
|
||||
mIpMap[pipPeer] = ppNew;
|
||||
|
||||
ppResult = ppNew;
|
||||
// ++miConnectStarting;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Found it. Already connected.
|
||||
|
||||
nothing();
|
||||
}
|
||||
}
|
||||
|
||||
if (ppResult)
|
||||
{
|
||||
Log(lsINFO) << "Pool: Connecting: " << ADDRESS_SHARED(ppResult) << ": " << strIp << " " << iPort;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Found it. Already connected or connecting.
|
||||
|
||||
bAccept = false;
|
||||
Log(lsINFO) << "Pool: Already connected: " << strIp << " " << iPort;
|
||||
}
|
||||
|
||||
return bAccept;
|
||||
}
|
||||
|
||||
bool ConnectionPool::connectTo(const std::string& strIp, int iPort)
|
||||
{
|
||||
bool bConnecting;
|
||||
ipPort ip = make_pair(strIp, iPort);
|
||||
|
||||
boost::unordered_map<ipPort, Peer::pointer>::iterator it;
|
||||
|
||||
boost::mutex::scoped_lock sl(mPeerLock);
|
||||
|
||||
it = mIpMap.find(ip);
|
||||
|
||||
if (it == mIpMap.end())
|
||||
{
|
||||
// Did not find it. Not already connecting or connected.
|
||||
std::cerr << "ConnectionPool::connectTo: Connecting: "
|
||||
<< strIp << " " << iPort << std::endl;
|
||||
|
||||
Peer::pointer peer(Peer::create(theApp->getIOService(), mCtx));
|
||||
|
||||
mIpMap[ip] = peer;
|
||||
|
||||
peer->connect(strIp, iPort);
|
||||
|
||||
// ++miConnectStarting;
|
||||
|
||||
bConnecting = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Found it. Already connected.
|
||||
std::cerr << "ConnectionPool::connectTo: Already connected: "
|
||||
<< strIp << " " << iPort << std::endl;
|
||||
|
||||
bConnecting = false;
|
||||
}
|
||||
|
||||
return bConnecting;
|
||||
return ppResult;
|
||||
}
|
||||
|
||||
// Returns information on verified peers.
|
||||
Json::Value ConnectionPool::getPeersJson()
|
||||
{
|
||||
Json::Value ret(Json::arrayValue);
|
||||
@@ -316,93 +333,228 @@ std::vector<Peer::pointer> ConnectionPool::getPeerVector()
|
||||
}
|
||||
|
||||
// Now know peer's node public key. Determine if we want to stay connected.
|
||||
bool ConnectionPool::peerConnected(Peer::pointer peer, const NewcoinAddress& na)
|
||||
// <-- bNew: false = redundant
|
||||
bool ConnectionPool::peerConnected(Peer::pointer peer, const NewcoinAddress& naPeer, const std::string& strIP, int iPort)
|
||||
{
|
||||
bool bSuccess;
|
||||
bool bNew = false;
|
||||
|
||||
std::cerr << "ConnectionPool::peerConnected: " << na.humanNodePublic()
|
||||
<< " " << peer->getIP() << " " << peer->getPort()
|
||||
<< std::endl;
|
||||
assert(!!peer);
|
||||
if (na == theApp->getWallet().getNodePublic())
|
||||
|
||||
if (naPeer == theApp->getWallet().getNodePublic())
|
||||
{
|
||||
std::cerr << "ConnectionPool::peerConnected: To self." << std::endl;
|
||||
bSuccess = false;
|
||||
Log(lsINFO) << "Pool: Connected: self: " << ADDRESS_SHARED(peer) << ": " << naPeer.humanNodePublic() << " " << strIP << " " << iPort;
|
||||
}
|
||||
else
|
||||
{
|
||||
boost::mutex::scoped_lock sl(mPeerLock);
|
||||
boost::unordered_map<NewcoinAddress, Peer::pointer>::iterator itCm = mConnectedMap.find(naPeer);
|
||||
|
||||
mConnectedMap[na] = peer;
|
||||
bSuccess = true;
|
||||
if (itCm == mConnectedMap.end())
|
||||
{
|
||||
// New connection.
|
||||
Log(lsINFO) << "Pool: Connected: new: " << ADDRESS_SHARED(peer) << ": " << naPeer.humanNodePublic() << " " << strIP << " " << iPort;
|
||||
|
||||
mConnectedMap[naPeer] = peer;
|
||||
bNew = true;
|
||||
}
|
||||
// Found in map, already connected.
|
||||
else if (!strIP.empty())
|
||||
{
|
||||
// Was an outbound connection, we know IP and port.
|
||||
// Note in previous connection how to reconnect.
|
||||
if (itCm->second->getIP().empty())
|
||||
{
|
||||
// Old peer did not know it's IP.
|
||||
Log(lsINFO) << "Pool: Connected: redundant: outbound: " << ADDRESS_SHARED(peer) << " discovered: " << ADDRESS_SHARED(itCm->second) << ": " << strIP << " " << iPort;
|
||||
|
||||
itCm->second->setIpPort(strIP, iPort);
|
||||
|
||||
// Add old connection to identified connection list.
|
||||
mIpMap[make_pair(strIP, iPort)] = itCm->second;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Old peer knew its IP. Do nothing.
|
||||
Log(lsINFO) << "Pool: Connected: redundant: outbound: rediscovered: " << ADDRESS_SHARED(peer) << " " << strIP << " " << iPort;
|
||||
|
||||
nothing();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Log(lsINFO) << "Pool: Connected: redundant: inbound: " << ADDRESS_SHARED(peer) << " " << strIP << " " << iPort;
|
||||
|
||||
nothing();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return bSuccess;
|
||||
return bNew;
|
||||
}
|
||||
|
||||
void ConnectionPool::peerDisconnected(Peer::pointer peer, const ipPort& ipPeer, const NewcoinAddress& naPeer)
|
||||
// We maintain a map of public key to peer for connected and verified peers. Maintain it.
|
||||
void ConnectionPool::peerDisconnected(Peer::pointer peer, const NewcoinAddress& naPeer)
|
||||
{
|
||||
std::cerr << "ConnectionPool::peerDisconnected: " << ipPeer.first << " " << ipPeer.second << std::endl;
|
||||
|
||||
boost::mutex::scoped_lock sl(mPeerLock);
|
||||
|
||||
if (naPeer.isValid())
|
||||
{
|
||||
boost::unordered_map<NewcoinAddress, Peer::pointer>::iterator itCm;
|
||||
|
||||
boost::mutex::scoped_lock sl(mPeerLock);
|
||||
|
||||
itCm = mConnectedMap.find(naPeer);
|
||||
|
||||
if (itCm == mConnectedMap.end())
|
||||
{
|
||||
// Did not find it. Not already connecting or connected.
|
||||
std::cerr << "Internal Error: peer connection was inconsistent." << std::endl;
|
||||
// XXX Bad error.
|
||||
Log(lsWARNING) << "Pool: disconnected: Internal Error: mConnectedMap was inconsistent.";
|
||||
// XXX Maybe bad error, considering we have racing connections, may not so bad.
|
||||
}
|
||||
else if (itCm->second != peer)
|
||||
{
|
||||
Log(lsWARNING) << "Pool: disconected: non canonical entry";
|
||||
|
||||
nothing();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Found it. Delete it.
|
||||
mConnectedMap.erase(itCm);
|
||||
|
||||
Log(lsINFO) << "Pool: disconnected: " << naPeer.humanNodePublic() << " " << peer->getIP() << " " << peer->getPort();
|
||||
}
|
||||
}
|
||||
|
||||
boost::unordered_map<ipPort, Peer::pointer>::iterator itIp;
|
||||
|
||||
itIp = mIpMap.find(ipPeer);
|
||||
|
||||
if (itIp == mIpMap.end())
|
||||
{
|
||||
// Did not find it. Not already connecting or connected.
|
||||
std::cerr << "Internal Error: peer wasn't connected: "
|
||||
<< ipPeer.first << " " << ipPeer.second << std::endl;
|
||||
// XXX Bad error.
|
||||
}
|
||||
else
|
||||
{
|
||||
// Found it. Delete it.
|
||||
mIpMap.erase(itIp);
|
||||
Log(lsINFO) << "Pool: disconnected: anonymous: " << peer->getIP() << " " << peer->getPort();
|
||||
}
|
||||
}
|
||||
|
||||
void ConnectionPool::peerFailed(const std::string& strIp, int iPort)
|
||||
// Schedule for immediate scanning, if not already scheduled.
|
||||
//
|
||||
// <-- true, scanRefresh needed.
|
||||
bool ConnectionPool::peerScanSet(const std::string& strIp, int iPort)
|
||||
{
|
||||
// If the fail was our scan, we are no longer scanning.
|
||||
if (bScanning && !mScanIp.compare(strIp) && mScanPort == iPort)
|
||||
{
|
||||
bScanning = false;
|
||||
std::string strIpPort = str(boost::format("%s %d") % strIp % iPort);
|
||||
bool bScanDirty = false;
|
||||
|
||||
// Look for more to scan.
|
||||
scanRefresh();
|
||||
}
|
||||
}
|
||||
ScopedLock sl(theApp->getWalletDB()->getDBLock());
|
||||
Database* db = theApp->getWalletDB()->getDB();
|
||||
|
||||
void ConnectionPool::peerVerified(const std::string& strIp, int iPort)
|
||||
{
|
||||
if (bScanning && !mScanIp.compare(strIp), mScanPort == iPort)
|
||||
if (db->executeSQL(str(boost::format("SELECT ScanNext FROM PeerIps WHERE IpPort=%s;")
|
||||
% sqlEscape(strIpPort)))
|
||||
&& db->startIterRows())
|
||||
{
|
||||
std::string strIpPort = str(boost::format("%s %d") % strIp % iPort);
|
||||
// Scan completed successfully.
|
||||
if (db->getNull("ScanNext"))
|
||||
{
|
||||
// Non-scanning connection terminated. Schedule for scanning.
|
||||
int iInterval = theConfig.PEER_SCAN_INTERVAL_MIN;
|
||||
boost::posix_time::ptime tpNow = boost::posix_time::second_clock::universal_time();
|
||||
boost::posix_time::ptime tpNext = tpNow + boost::posix_time::seconds(iInterval);
|
||||
|
||||
Log(lsINFO) << str(boost::format("Pool: Scan: schedule create: %s %s (next %s, delay=%d)")
|
||||
% mScanIp % mScanPort % tpNext % (tpNext-tpNow).total_seconds());
|
||||
|
||||
db->executeSQL(str(boost::format("UPDATE PeerIps SET ScanNext=%d,ScanInterval=%d WHERE IpPort=%s;")
|
||||
% iToSeconds(tpNext)
|
||||
% iInterval
|
||||
% db->escape(strIpPort)));
|
||||
|
||||
bScanDirty = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Scan connection terminated, already scheduled for retry.
|
||||
boost::posix_time::ptime tpNow = boost::posix_time::second_clock::universal_time();
|
||||
boost::posix_time::ptime tpNext = ptFromSeconds(db->getInt("ScanNext"));
|
||||
|
||||
Log(lsINFO) << str(boost::format("Pool: Scan: schedule exists: %s %s (next %s, delay=%d)")
|
||||
% mScanIp % mScanPort % tpNext % (tpNext-tpNow).total_seconds());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Log(lsWARNING) << "Pool: Scan: peer wasn't in PeerIps: " << strIp << " " << iPort;
|
||||
}
|
||||
|
||||
return bScanDirty;
|
||||
}
|
||||
|
||||
// --> strIp: not empty
|
||||
void ConnectionPool::peerClosed(Peer::pointer peer, const std::string& strIp, int iPort)
|
||||
{
|
||||
ipPort ipPeer = make_pair(strIp, iPort);
|
||||
bool bScanRefresh = false;
|
||||
|
||||
// If the connection was our scan, we are no longer scanning.
|
||||
if (mScanning && mScanning == peer)
|
||||
{
|
||||
Log(lsINFO) << "Pool: Scan: scan fail: " << strIp << " " << iPort;
|
||||
|
||||
mScanning = Peer::pointer(); // No longer scanning.
|
||||
bScanRefresh = true; // Look for more to scan.
|
||||
}
|
||||
|
||||
// Determine if closed peer was redundant.
|
||||
bool bRedundant = true;
|
||||
{
|
||||
boost::mutex::scoped_lock sl(mPeerLock);
|
||||
boost::unordered_map<ipPort, Peer::pointer>::iterator itIp;
|
||||
|
||||
itIp = mIpMap.find(ipPeer);
|
||||
|
||||
if (itIp == mIpMap.end())
|
||||
{
|
||||
// Did not find it. Not already connecting or connected.
|
||||
Log(lsWARNING) << "Pool: Closed: UNEXPECTED: " << ADDRESS_SHARED(peer) << ": " << strIp << " " << iPort;
|
||||
// XXX Internal error.
|
||||
}
|
||||
else if (mIpMap[ipPeer] == peer)
|
||||
{
|
||||
// We were the identified connection.
|
||||
Log(lsINFO) << "Pool: Closed: identified: " << ADDRESS_SHARED(peer) << ": " << strIp << " " << iPort;
|
||||
|
||||
// Delete our entry.
|
||||
mIpMap.erase(itIp);
|
||||
|
||||
bRedundant = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Found it. But, we were redundent.
|
||||
Log(lsINFO) << "Pool: Closed: redundant: " << ADDRESS_SHARED(peer) << ": " << strIp << " " << iPort;
|
||||
}
|
||||
}
|
||||
|
||||
if (!bRedundant)
|
||||
{
|
||||
// If closed was not redundant schedule if not already scheduled.
|
||||
bScanRefresh = peerScanSet(ipPeer.first, ipPeer.second) || bScanRefresh;
|
||||
}
|
||||
|
||||
if (bScanRefresh)
|
||||
scanRefresh();
|
||||
}
|
||||
|
||||
void ConnectionPool::peerVerified(Peer::pointer peer)
|
||||
{
|
||||
if (mScanning && mScanning == peer)
|
||||
{
|
||||
// Scan completed successfully.
|
||||
std::string strIp = peer->getIP();
|
||||
int iPort = peer->getPort();
|
||||
|
||||
std::string strIpPort = str(boost::format("%s %d") % strIp % iPort);
|
||||
|
||||
Log(lsINFO) << str(boost::format("Pool: Scan: connected: %s %s %s (scanned)") % ADDRESS_SHARED(peer) % strIp % iPort);
|
||||
|
||||
if (peer->getNodePublic() == theApp->getWallet().getNodePublic())
|
||||
{
|
||||
// Talking to ourself. We will just back off. This lets us maybe advertise our outside address.
|
||||
|
||||
nothing(); // Do nothing, leave scheduled scanning.
|
||||
}
|
||||
else
|
||||
{
|
||||
// Talking with a different peer.
|
||||
ScopedLock sl(theApp->getWalletDB()->getDBLock());
|
||||
Database *db=theApp->getWalletDB()->getDB();
|
||||
|
||||
@@ -411,8 +563,9 @@ void ConnectionPool::peerVerified(const std::string& strIp, int iPort)
|
||||
// XXX Check error.
|
||||
}
|
||||
|
||||
bScanning = false;
|
||||
scanRefresh();
|
||||
mScanning = Peer::pointer();
|
||||
|
||||
scanRefresh(); // Continue scanning.
|
||||
}
|
||||
}
|
||||
|
||||
@@ -435,10 +588,10 @@ void ConnectionPool::scanHandler(const boost::system::error_code& ecResult)
|
||||
// Scan ips as per db entries.
|
||||
void ConnectionPool::scanRefresh()
|
||||
{
|
||||
if (bScanning)
|
||||
if (mScanning)
|
||||
{
|
||||
// Currently scanning, will scan again after completion.
|
||||
std::cerr << "scanRefresh: already scanning" << std::endl;
|
||||
Log(lsTRACE) << "Pool: Scan: already scanning";
|
||||
|
||||
nothing();
|
||||
}
|
||||
@@ -451,8 +604,8 @@ void ConnectionPool::scanRefresh()
|
||||
int iInterval;
|
||||
|
||||
{
|
||||
ScopedLock sl(theApp->getWalletDB()->getDBLock());
|
||||
Database *db=theApp->getWalletDB()->getDB();
|
||||
ScopedLock sl(theApp->getWalletDB()->getDBLock());
|
||||
Database* db = theApp->getWalletDB()->getDB();
|
||||
|
||||
if (db->executeSQL("SELECT * FROM PeerIps INDEXED BY PeerScanIndex WHERE ScanNext NOT NULL ORDER BY ScanNext LIMIT 1;")
|
||||
&& db->startIterRows())
|
||||
@@ -475,7 +628,7 @@ void ConnectionPool::scanRefresh()
|
||||
|
||||
if (tpNow.is_not_a_date_time())
|
||||
{
|
||||
std::cerr << "scanRefresh: no scan needed." << std::endl;
|
||||
Log(lsINFO) << "Pool: Scan: stop.";
|
||||
|
||||
(void) mScanTimer.cancel();
|
||||
}
|
||||
@@ -486,14 +639,15 @@ void ConnectionPool::scanRefresh()
|
||||
|
||||
(void) mScanTimer.cancel();
|
||||
|
||||
std::cerr << "scanRefresh: scanning: " << mScanIp << " " << mScanPort << std::endl;
|
||||
bScanning = true;
|
||||
|
||||
iInterval *= 2;
|
||||
iInterval = MAX(iInterval, theConfig.PEER_SCAN_INTERVAL_MIN);
|
||||
|
||||
tpNext = tpNow + boost::posix_time::seconds(iInterval);
|
||||
|
||||
Log(lsINFO) << str(boost::format("Pool: Scan: Now: %s %s (next %s, delay=%d)")
|
||||
% mScanIp % mScanPort % tpNext % (tpNext-tpNow).total_seconds());
|
||||
|
||||
iInterval *= 2;
|
||||
|
||||
{
|
||||
ScopedLock sl(theApp->getWalletDB()->getDBLock());
|
||||
Database *db=theApp->getWalletDB()->getDB();
|
||||
@@ -505,7 +659,8 @@ void ConnectionPool::scanRefresh()
|
||||
// XXX Check error.
|
||||
}
|
||||
|
||||
if (!connectTo(mScanIp, mScanPort))
|
||||
mScanning = peerConnect(mScanIp, mScanPort);
|
||||
if (!mScanning)
|
||||
{
|
||||
// Already connected. Try again.
|
||||
scanRefresh();
|
||||
@@ -513,7 +668,8 @@ void ConnectionPool::scanRefresh()
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "scanRefresh: next due: " << tpNow << std::endl;
|
||||
Log(lsINFO) << str(boost::format("Pool: Scan: Next: %s (next %s, delay=%d)")
|
||||
% strIpPort % tpNext % (tpNext-tpNow).total_seconds());
|
||||
|
||||
mScanTimer.expires_at(tpNext);
|
||||
mScanTimer.async_wait(boost::bind(&ConnectionPool::scanHandler, this, _1));
|
||||
|
||||
@@ -20,28 +20,36 @@ private:
|
||||
typedef std::pair<ipPort, Peer::pointer> pipPeer;
|
||||
|
||||
// Peers we are connecting with and non-thin peers we are connected to.
|
||||
// Only peers we know the connection ip for are listed.
|
||||
// We know the ip and port for:
|
||||
// - All outbound connections
|
||||
// - Some inbound connections (which we figured out).
|
||||
boost::unordered_map<ipPort, Peer::pointer> mIpMap;
|
||||
|
||||
// Non-thin peers which we are connected to.
|
||||
// Peers we have the public key for.
|
||||
boost::unordered_map<NewcoinAddress, Peer::pointer> mConnectedMap;
|
||||
|
||||
boost::asio::ssl::context mCtx;
|
||||
|
||||
bool bScanning;
|
||||
Peer::pointer mScanning;
|
||||
boost::asio::deadline_timer mScanTimer;
|
||||
std::string mScanIp;
|
||||
int mScanPort;
|
||||
|
||||
void scanHandler(const boost::system::error_code& ecResult);
|
||||
void scanHandler(const boost::system::error_code& ecResult);
|
||||
|
||||
boost::asio::deadline_timer mPolicyTimer;
|
||||
|
||||
void policyHandler(const boost::system::error_code& ecResult);
|
||||
void policyHandler(const boost::system::error_code& ecResult);
|
||||
|
||||
// Peers we are establishing a connection with as a client.
|
||||
// int miConnectStarting;
|
||||
|
||||
bool peerAvailable(std::string& strIp, int& iPort);
|
||||
bool peerAvailable(std::string& strIp, int& iPort);
|
||||
bool peerScanSet(const std::string& strIp, int iPort);
|
||||
|
||||
Peer::pointer peerConnect(const std::string& strIp, int iPort);
|
||||
|
||||
public:
|
||||
ConnectionPool(boost::asio::io_service& io_service);
|
||||
@@ -54,7 +62,7 @@ public:
|
||||
|
||||
// Manual connection request.
|
||||
// Queue for immediate scanning.
|
||||
bool connectTo(const std::string& strIp, int iPort);
|
||||
void connectTo(const std::string& strIp, int iPort);
|
||||
|
||||
//
|
||||
// Peer connectivity notification.
|
||||
@@ -62,20 +70,18 @@ public:
|
||||
bool getTopNAddrs(int n,std::vector<std::string>& addrs);
|
||||
bool savePeer(const std::string& strIp, int iPort, char code);
|
||||
|
||||
// Inbound connection, false=reject
|
||||
bool peerRegister(Peer::pointer peer, const std::string& strIp, int iPort);
|
||||
|
||||
// We know peers node public key. false=reject
|
||||
bool peerConnected(Peer::pointer peer, const NewcoinAddress& na);
|
||||
// We know peers node public key.
|
||||
// <-- bool: false=reject
|
||||
bool peerConnected(Peer::pointer peer, const NewcoinAddress& naPeer, const std::string& strIP, int iPort);
|
||||
|
||||
// No longer connected.
|
||||
void peerDisconnected(Peer::pointer peer, const ipPort& ipPeer, const NewcoinAddress& naPeer);
|
||||
void peerDisconnected(Peer::pointer peer, const NewcoinAddress& naPeer);
|
||||
|
||||
// As client accepted.
|
||||
void peerVerified(const std::string& strIp, int iPort);
|
||||
void peerVerified(Peer::pointer peer);
|
||||
|
||||
// As client failed connect and be accepted.
|
||||
void peerFailed(const std::string& strIp, int iPort);
|
||||
void peerClosed(Peer::pointer peer, const std::string& strIp, int iPort);
|
||||
|
||||
Json::Value getPeersJson();
|
||||
std::vector<Peer::pointer> getPeerVector();
|
||||
|
||||
@@ -42,13 +42,6 @@ bool u160ToHuman(uint160& buf, std::string& retStr)
|
||||
|
||||
#endif
|
||||
|
||||
base_uint160 uint256::to160() const
|
||||
{
|
||||
uint160 m;
|
||||
memcpy(m.begin(), begin(), m.size());
|
||||
return m;
|
||||
}
|
||||
|
||||
base_uint256 uint160::to256() const
|
||||
{
|
||||
uint256 m;
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
// Transaction database holds transactions and public keys
|
||||
const char *TxnDBInit[] = {
|
||||
"BEGIN TRANSACTION;",
|
||||
|
||||
"CREATE TABLE Transactions ( \
|
||||
TransID CHARACTER(64) PRIMARY KEY, \
|
||||
TransType CHARACTER(24), \
|
||||
@@ -21,13 +23,17 @@ const char *TxnDBInit[] = {
|
||||
LedgerSeq BIGINT UNSIGNED \
|
||||
);",
|
||||
"CREATE INDEX AcctTxindex ON \
|
||||
AccountTransactions(Account, LedgerSeq, TransID);"
|
||||
AccountTransactions(Account, LedgerSeq, TransID);",
|
||||
|
||||
"END TRANSACTION;"
|
||||
};
|
||||
|
||||
int TxnDBCount = sizeof(TxnDBInit) / sizeof(const char *);
|
||||
|
||||
// Ledger database holds ledgers and ledger confirmations
|
||||
const char *LedgerDBInit[] = {
|
||||
"BEGIN TRANSACTION;",
|
||||
|
||||
"CREATE TABLE Ledgers ( \
|
||||
LedgerHash CHARACTER(64) PRIMARY KEY, \
|
||||
LedgerSeq BIGINT UNSIGNED, \
|
||||
@@ -46,8 +52,9 @@ const char *LedgerDBInit[] = {
|
||||
Signature BLOB \
|
||||
);",
|
||||
"CREATE INDEX LedgerConfByHash ON \
|
||||
LedgerConfirmations(LedgerHash)"
|
||||
LedgerConfirmations(LedgerHash)",
|
||||
#endif
|
||||
"END TRANSACTION;"
|
||||
};
|
||||
|
||||
int LedgerDBCount = sizeof(LedgerDBInit) / sizeof(const char *);
|
||||
@@ -55,6 +62,8 @@ int LedgerDBCount = sizeof(LedgerDBInit) / sizeof(const char *);
|
||||
// Wallet database holds local accounts and trusted nodes
|
||||
const char *WalletDBInit[] = {
|
||||
// Node identity must be persisted for CAS routing and responsibilities.
|
||||
"BEGIN TRANSACTION;",
|
||||
|
||||
"CREATE TABLE NodeIdentity ( \
|
||||
PublicKey CHARACTER(53), \
|
||||
PrivateKey CHARACTER(52), \
|
||||
@@ -214,20 +223,24 @@ const char *WalletDBInit[] = {
|
||||
// Delay between scans.
|
||||
"CREATE TABLE PeerIps ( \
|
||||
IpPort TEXT NOT NULL PRIMARY KEY, \
|
||||
Score INTEGER NOT NULL, \
|
||||
Score INTEGER NOT NULL DEFAULT 0, \
|
||||
Source CHARACTER(1) NOT NULL, \
|
||||
ScanNext DATETIME DEFAULT 0, \
|
||||
ScanInterval INTEGER NOT NULL DEFAULT 0 \
|
||||
);",
|
||||
|
||||
"CREATE INDEX PeerScanIndex ON \
|
||||
PeerIps(ScanNext);"
|
||||
PeerIps(ScanNext);",
|
||||
|
||||
"END TRANSACTION;"
|
||||
};
|
||||
|
||||
int WalletDBCount = sizeof(WalletDBInit) / sizeof(const char *);
|
||||
|
||||
// Hash node database holds nodes indexed by hash
|
||||
const char *HashNodeDBInit[] = {
|
||||
"BEGIN TRANSACTION;",
|
||||
|
||||
"CREATE TABLE CommittedObjects ( \
|
||||
Hash CHARACTER(64) PRIMARY KEY, \
|
||||
ObjType CHAR(1) NOT NULL, \
|
||||
@@ -236,7 +249,9 @@ const char *HashNodeDBInit[] = {
|
||||
);",
|
||||
|
||||
"CREATE INDEX ObjectLocate ON \
|
||||
CommittedObjects(LedgerIndex, ObjType);"
|
||||
CommittedObjects(LedgerIndex, ObjType);",
|
||||
|
||||
"END TRANSACTION;"
|
||||
};
|
||||
|
||||
int HashNodeDBCount = sizeof(HashNodeDBInit) / sizeof(const char *);
|
||||
|
||||
@@ -42,7 +42,6 @@ Ledger::Ledger(const uint256 &parentHash, const uint256 &transHash, const uint25
|
||||
mTotCoins(totCoins), mCloseTime(timeStamp), mLedgerSeq(ledgerSeq), mLedgerInterval(LEDGER_INTERVAL),
|
||||
mClosed(false), mValidHash(false), mAccepted(false), mImmutable(false)
|
||||
{
|
||||
assert(mParentHash.isNonZero());
|
||||
updateHash();
|
||||
}
|
||||
|
||||
@@ -109,7 +108,7 @@ Ledger::Ledger(const std::string& rawLedger) : mCloseTime(0),
|
||||
|
||||
void Ledger::updateHash()
|
||||
{
|
||||
if(!mImmutable)
|
||||
if (!mImmutable)
|
||||
{
|
||||
if (mTransactionMap) mTransHash = mTransactionMap->getHash();
|
||||
else mTransHash.zero();
|
||||
@@ -236,7 +235,6 @@ uint256 Ledger::getHash()
|
||||
|
||||
void Ledger::saveAcceptedLedger(Ledger::pointer ledger)
|
||||
{
|
||||
|
||||
std::string sql="INSERT INTO Ledgers "
|
||||
"(LedgerHash,LedgerSeq,PrevHash,TotalCoins,ClosingTime,AccountSetHash,TransSetHash) VALUES ('";
|
||||
sql.append(ledger->getHash().GetHex());
|
||||
@@ -329,10 +327,9 @@ Ledger::pointer Ledger::getSQL(const std::string& sql)
|
||||
uint32 ledgerSeq;
|
||||
std::string hash;
|
||||
|
||||
if(1)
|
||||
{
|
||||
ScopedLock sl(theApp->getLedgerDB()->getDBLock());
|
||||
Database *db = theApp->getLedgerDB()->getDB();
|
||||
ScopedLock sl(theApp->getLedgerDB()->getDBLock());
|
||||
|
||||
if (!db->executeSQL(sql) || !db->startIterRows())
|
||||
return Ledger::pointer();
|
||||
@@ -351,7 +348,8 @@ Ledger::pointer Ledger::getSQL(const std::string& sql)
|
||||
db->endIterRows();
|
||||
}
|
||||
|
||||
Ledger::pointer ret=boost::make_shared<Ledger>(prevHash, transHash, accountHash, totCoins, closingTime, ledgerSeq);
|
||||
Ledger::pointer ret =
|
||||
boost::make_shared<Ledger>(prevHash, transHash, accountHash, totCoins, closingTime, ledgerSeq);
|
||||
if (ret->getHash() != ledgerHash)
|
||||
{
|
||||
assert(false);
|
||||
@@ -465,12 +463,18 @@ void Ledger::setCloseTime(boost::posix_time::ptime ptm)
|
||||
mCloseTime = iToSeconds(ptm);
|
||||
}
|
||||
|
||||
uint64 Ledger::sGenesisClose = 0;
|
||||
|
||||
uint64 Ledger::getNextLedgerClose() const
|
||||
{
|
||||
if (mCloseTime == 0)
|
||||
{
|
||||
uint64 closeTime = theApp->getOPs().getNetworkTimeNC() + mLedgerInterval - 1;
|
||||
return closeTime - (closeTime % mLedgerInterval);
|
||||
if (sGenesisClose == 0)
|
||||
{
|
||||
uint64 closeTime = theApp->getOPs().getNetworkTimeNC() + mLedgerInterval - 1;
|
||||
sGenesisClose = closeTime - (closeTime % mLedgerInterval);
|
||||
}
|
||||
return sGenesisClose;
|
||||
}
|
||||
return mCloseTime + mLedgerInterval;
|
||||
}
|
||||
|
||||
@@ -67,6 +67,8 @@ private:
|
||||
uint16 mLedgerInterval;
|
||||
bool mClosed, mValidHash, mAccepted, mImmutable;
|
||||
|
||||
static uint64 sGenesisClose;
|
||||
|
||||
SHAMap::pointer mTransactionMap, mAccountStateMap;
|
||||
|
||||
mutable boost::recursive_mutex mLock;
|
||||
@@ -96,9 +98,10 @@ public:
|
||||
void updateHash();
|
||||
void setClosed() { mClosed = true; }
|
||||
void setAccepted() { mAccepted = true; }
|
||||
void setImmutable() { mImmutable = true; }
|
||||
void setImmutable() { updateHash(); mImmutable = true; }
|
||||
bool isClosed() { return mClosed; }
|
||||
bool isAccepted() { return mAccepted; }
|
||||
bool isImmutable() { return mImmutable; }
|
||||
|
||||
// This ledger has closed, will never be accepted, and is accepting
|
||||
// new transactions to be re-repocessed when do accept a new last-closed ledger
|
||||
|
||||
@@ -254,7 +254,7 @@ void PeerSet::sendRequest(const newcoin::TMGetLedger& tmGL)
|
||||
while (it != mPeers.end())
|
||||
{
|
||||
if (it->expired())
|
||||
mPeers.erase(it++);
|
||||
it = mPeers.erase(it);
|
||||
else
|
||||
{
|
||||
// FIXME: Track last peer sent to and time sent
|
||||
@@ -370,10 +370,10 @@ bool LedgerAcquireMaster::hasLedger(const uint256& hash)
|
||||
return mLedgers.find(hash) != mLedgers.end();
|
||||
}
|
||||
|
||||
bool LedgerAcquireMaster::dropLedger(const uint256& hash)
|
||||
void LedgerAcquireMaster::dropLedger(const uint256& hash)
|
||||
{
|
||||
boost::mutex::scoped_lock sl(mLock);
|
||||
return mLedgers.erase(hash);
|
||||
mLedgers.erase(hash);
|
||||
}
|
||||
|
||||
bool LedgerAcquireMaster::gotLedgerData(newcoin::TMLedgerData& packet, Peer::pointer peer)
|
||||
|
||||
@@ -128,7 +128,7 @@ public:
|
||||
LedgerAcquire::pointer findCreate(const uint256& hash);
|
||||
LedgerAcquire::pointer find(const uint256& hash);
|
||||
bool hasLedger(const uint256& ledgerHash);
|
||||
bool dropLedger(const uint256& ledgerHash);
|
||||
void dropLedger(const uint256& ledgerHash);
|
||||
bool gotLedgerData(newcoin::TMLedgerData& packet, Peer::pointer);
|
||||
};
|
||||
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
// #define LC_DEBUG
|
||||
|
||||
// TODO: If we don't have the previousLCL, check if we got it. If so, change modes
|
||||
|
||||
TransactionAcquire::TransactionAcquire(const uint256& hash)
|
||||
: PeerSet(hash, 1), mFilter(&theApp->getNodeCache()), mHaveRoot(false)
|
||||
{
|
||||
@@ -188,18 +190,27 @@ int LCTransaction::getAgreeLevel()
|
||||
return (mNays * 100 + 100) / (mYays + mNays + 1);
|
||||
}
|
||||
|
||||
LedgerConsensus::LedgerConsensus(Ledger::pointer previousLedger, uint32 closeTime)
|
||||
: mState(lcsPRE_CLOSE), mCloseTime(closeTime), mPreviousLedger(previousLedger)
|
||||
LedgerConsensus::LedgerConsensus(const uint256& prevLCLHash, Ledger::pointer previousLedger, uint32 closeTime)
|
||||
: mState(lcsPRE_CLOSE), mCloseTime(closeTime), mPrevLedgerHash(prevLCLHash), mPreviousLedger(previousLedger)
|
||||
{
|
||||
mValSeed = theConfig.VALIDATION_SEED;
|
||||
Log(lsDEBUG) << "Creating consensus object";
|
||||
Log(lsTRACE) << "LCL:" << previousLedger->getHash().GetHex() <<", ct=" << closeTime;
|
||||
if (previousLedger->getHash() != prevLCLHash)
|
||||
mHaveCorrectLCL = mProposing = mValidating = false;
|
||||
else if (mValSeed.isValid())
|
||||
{
|
||||
mValidating = true;
|
||||
mProposing = theApp->getOPs().getOperatingMode() == NetworkOPs::omFULL;
|
||||
}
|
||||
else mProposing = mValidating = false;
|
||||
}
|
||||
|
||||
void LedgerConsensus::takeInitialPosition(Ledger::pointer initialLedger)
|
||||
{
|
||||
SHAMap::pointer initialSet = initialLedger->peekTransactionMap()->snapShot(false);
|
||||
uint256 txSet = initialSet->getHash();
|
||||
assert (initialLedger->getParentHash() == mPreviousLedger->getHash());
|
||||
assert (!mHaveCorrectLCL || (initialLedger->getParentHash() == mPreviousLedger->getHash()));
|
||||
|
||||
// if any peers have taken a contrary position, process disputes
|
||||
boost::unordered_set<uint256> found;
|
||||
@@ -215,10 +226,13 @@ void LedgerConsensus::takeInitialPosition(Ledger::pointer initialLedger)
|
||||
}
|
||||
}
|
||||
|
||||
mOurPosition = boost::make_shared<LedgerProposal>
|
||||
(theConfig.VALIDATION_SEED, initialLedger->getParentHash(), txSet);
|
||||
mapComplete(txSet, initialSet);
|
||||
propose(std::vector<uint256>(), std::vector<uint256>());
|
||||
if (mValidating)
|
||||
mOurPosition = boost::make_shared<LedgerProposal>
|
||||
(mValSeed, initialLedger->getParentHash(), txSet);
|
||||
else
|
||||
mOurPosition = boost::make_shared<LedgerProposal>(initialLedger->getParentHash(), txSet);
|
||||
mapComplete(txSet, initialSet, false);
|
||||
if (mProposing) propose(std::vector<uint256>(), std::vector<uint256>());
|
||||
}
|
||||
|
||||
void LedgerConsensus::createDisputes(SHAMap::pointer m1, SHAMap::pointer m2)
|
||||
@@ -241,9 +255,10 @@ void LedgerConsensus::createDisputes(SHAMap::pointer m1, SHAMap::pointer m2)
|
||||
}
|
||||
}
|
||||
|
||||
void LedgerConsensus::mapComplete(const uint256& hash, SHAMap::pointer map)
|
||||
void LedgerConsensus::mapComplete(const uint256& hash, SHAMap::pointer map, bool acquired)
|
||||
{
|
||||
Log(lsINFO) << "We have acquired TXS " << hash.GetHex();
|
||||
if (acquired)
|
||||
Log(lsINFO) << "We have acquired TXS " << hash.GetHex();
|
||||
mAcquiring.erase(hash);
|
||||
|
||||
if (!map)
|
||||
@@ -254,10 +269,7 @@ void LedgerConsensus::mapComplete(const uint256& hash, SHAMap::pointer map)
|
||||
}
|
||||
|
||||
if (mComplete.find(hash) != mComplete.end())
|
||||
{
|
||||
Log(lsERROR) << "Which we already had";
|
||||
return; // we already have this map
|
||||
}
|
||||
|
||||
if (mOurPosition && (map->getHash() != mOurPosition->getCurrentHash()))
|
||||
{ // this could create disputed transactions
|
||||
@@ -281,8 +293,8 @@ void LedgerConsensus::mapComplete(const uint256& hash, SHAMap::pointer map)
|
||||
}
|
||||
if (!peers.empty())
|
||||
adjustCount(map, peers);
|
||||
else if (!hash)
|
||||
Log(lsWARNING) << "By the time we got the map, no peers were proposing it";
|
||||
else if (acquired)
|
||||
Log(lsWARNING) << "By the time we got the map " << hash.GetHex() << " no peers were proposing it";
|
||||
|
||||
sendHaveTxSet(hash, true);
|
||||
}
|
||||
@@ -310,13 +322,24 @@ void LedgerConsensus::adjustCount(SHAMap::pointer map, const std::vector<uint160
|
||||
void LedgerConsensus::statusChange(newcoin::NodeEvent event, Ledger::pointer ledger)
|
||||
{ // Send a node status change message to our peers
|
||||
newcoin::TMStatusChange s;
|
||||
s.set_newevent(event);
|
||||
s.set_ledgerseq(ledger->getLedgerSeq());
|
||||
s.set_networktime(theApp->getOPs().getNetworkTimeNC());
|
||||
uint256 plhash = ledger->getParentHash();
|
||||
s.set_previousledgerhash(plhash.begin(), plhash.size());
|
||||
if (!mHaveCorrectLCL)
|
||||
{
|
||||
Log(lsTRACE) << "Telling peers we have lost sync";
|
||||
s.set_newevent(newcoin::neLOST_SYNC);
|
||||
}
|
||||
else
|
||||
{
|
||||
s.set_newevent(event);
|
||||
s.set_ledgerseq(ledger->getLedgerSeq());
|
||||
s.set_networktime(theApp->getOPs().getNetworkTimeNC());
|
||||
uint256 hash = ledger->getParentHash();
|
||||
s.set_previousledgerhash(hash.begin(), hash.size());
|
||||
hash = ledger->getHash();
|
||||
s.set_ledgerhash(hash.begin(), hash.size());
|
||||
}
|
||||
PackedMessage::pointer packet = boost::make_shared<PackedMessage>(s, newcoin::mtSTATUS_CHANGE);
|
||||
theApp->getConnectionPool().relayMessage(NULL, packet);
|
||||
Log(lsINFO) << "send status change to peer";
|
||||
}
|
||||
|
||||
void LedgerConsensus::abort()
|
||||
@@ -359,7 +382,8 @@ int LedgerConsensus::statePostClose(int secondsSinceClose)
|
||||
|
||||
int LedgerConsensus::stateEstablish(int secondsSinceClose)
|
||||
{ // we are establishing consensus
|
||||
updateOurPositions(secondsSinceClose);
|
||||
if (mProposing)
|
||||
updateOurPositions(secondsSinceClose);
|
||||
if (secondsSinceClose > LEDGER_MAX_CONVERGE)
|
||||
{
|
||||
Log(lsINFO) << "Converge cutoff";
|
||||
@@ -447,8 +471,8 @@ bool LedgerConsensus::updateOurPositions(int sinceClose)
|
||||
{
|
||||
uint256 newHash = ourPosition->getHash();
|
||||
mOurPosition->changePosition(newHash);
|
||||
propose(addedTx, removedTx);
|
||||
mapComplete(newHash, ourPosition);
|
||||
if (mProposing) propose(addedTx, removedTx);
|
||||
mapComplete(newHash, ourPosition, false);
|
||||
Log(lsINFO) << "We change our position to " << newHash.GetHex();
|
||||
}
|
||||
|
||||
@@ -468,7 +492,7 @@ SHAMap::pointer LedgerConsensus::getTransactionTree(const uint256& hash, bool do
|
||||
if (!hash)
|
||||
{
|
||||
SHAMap::pointer empty = boost::make_shared<SHAMap>();
|
||||
mapComplete(hash, empty);
|
||||
mapComplete(hash, empty, false);
|
||||
return empty;
|
||||
}
|
||||
acquiring = boost::make_shared<TransactionAcquire>(hash);
|
||||
@@ -505,7 +529,7 @@ void LedgerConsensus::startAcquiring(TransactionAcquire::pointer acquire)
|
||||
|
||||
void LedgerConsensus::propose(const std::vector<uint256>& added, const std::vector<uint256>& removed)
|
||||
{
|
||||
Log(lsDEBUG) << "We propose: " << mOurPosition->getCurrentHash().GetHex();
|
||||
Log(lsTRACE) << "We propose: " << mOurPosition->getCurrentHash().GetHex();
|
||||
newcoin::TMProposeSet prop;
|
||||
prop.set_currenttxhash(mOurPosition->getCurrentHash().begin(), 256 / 8);
|
||||
prop.set_proposeseq(mOurPosition->getProposeSeq());
|
||||
@@ -610,8 +634,7 @@ void LedgerConsensus::beginAccept()
|
||||
SHAMap::pointer consensusSet = mComplete[mOurPosition->getCurrentHash()];
|
||||
if (!consensusSet)
|
||||
{
|
||||
Log(lsFATAL) << "We don't have our own set";
|
||||
assert(false);
|
||||
Log(lsFATAL) << "We don't have a consensus set";
|
||||
abort();
|
||||
return;
|
||||
}
|
||||
@@ -642,7 +665,7 @@ void LedgerConsensus::applyTransaction(TransactionEngine& engine, SerializedTran
|
||||
}
|
||||
else if (result == 0)
|
||||
{
|
||||
Log(lsDEBUG) << " success";
|
||||
Log(lsTRACE) << " success";
|
||||
assert(ledger->hasTransaction(txn->getTransactionID()));
|
||||
}
|
||||
else
|
||||
@@ -696,7 +719,7 @@ void LedgerConsensus::applyTransactions(SHAMap::pointer set, Ledger::pointer led
|
||||
if (result <= 0)
|
||||
{
|
||||
if (result == 0) ++successes;
|
||||
failedTransactions.eraseInc(it);
|
||||
it = failedTransactions.erase(it);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -706,7 +729,7 @@ void LedgerConsensus::applyTransactions(SHAMap::pointer set, Ledger::pointer led
|
||||
catch (...)
|
||||
{
|
||||
Log(lsWARNING) << " Throws";
|
||||
failedTransactions.eraseInc(it);
|
||||
it = failedTransactions.erase(it);
|
||||
}
|
||||
}
|
||||
} while (successes > 0);
|
||||
@@ -717,7 +740,7 @@ void LedgerConsensus::accept(SHAMap::pointer set)
|
||||
assert(set->getHash() == mOurPosition->getCurrentHash());
|
||||
Log(lsINFO) << "Computing new LCL based on network consensus";
|
||||
Log(lsDEBUG) << "Consensus " << mOurPosition->getCurrentHash().GetHex();
|
||||
Log(lsDEBUG) << "Previous LCL " << mPreviousLedger->getHash().GetHex();
|
||||
Log(lsDEBUG) << "Previous LCL " << mPrevLedgerHash.GetHex();
|
||||
|
||||
Ledger::pointer newLCL = boost::make_shared<Ledger>(false, boost::ref(*mPreviousLedger));
|
||||
|
||||
@@ -728,7 +751,7 @@ void LedgerConsensus::accept(SHAMap::pointer set)
|
||||
Log(lsTRACE) << "newLCL before transactions";
|
||||
Json::Value p;
|
||||
newLCL->addJson(p, LEDGER_JSON_DUMP_TXNS | LEDGER_JSON_DUMP_STATE);
|
||||
ssw.write(std::cerr, p);
|
||||
ssw.write(Log(lsTRACE).ref(), p);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -740,15 +763,6 @@ void LedgerConsensus::accept(SHAMap::pointer set)
|
||||
uint256 newLCLHash = newLCL->getHash();
|
||||
Log(lsTRACE) << "newLCL " << newLCLHash.GetHex();
|
||||
|
||||
#ifdef DEBUG
|
||||
if (1)
|
||||
{
|
||||
Log(lsTRACE) << "newLCL after transactions";
|
||||
Json::Value p;
|
||||
newLCL->addJson(p, LEDGER_JSON_DUMP_TXNS | LEDGER_JSON_DUMP_STATE);
|
||||
ssw.write(std::cerr, p);
|
||||
}
|
||||
#endif
|
||||
|
||||
Ledger::pointer newOL = boost::make_shared<Ledger>(true, boost::ref(*newLCL));
|
||||
|
||||
@@ -758,14 +772,14 @@ void LedgerConsensus::accept(SHAMap::pointer set)
|
||||
Log(lsTRACE) << "newOL before transactions";
|
||||
Json::Value p;
|
||||
newOL->addJson(p, LEDGER_JSON_DUMP_TXNS | LEDGER_JSON_DUMP_STATE);
|
||||
ssw.write(std::cerr, p);
|
||||
ssw.write(Log(lsTRACE).ref(), p);
|
||||
}
|
||||
if (1)
|
||||
{
|
||||
Log(lsTRACE) << "current ledger";
|
||||
Json::Value p;
|
||||
theApp->getMasterLedger().getCurrentLedger()->addJson(p, LEDGER_JSON_DUMP_TXNS | LEDGER_JSON_DUMP_STATE);
|
||||
ssw.write(std::cerr, p);
|
||||
ssw.write(Log(lsTRACE).ref(), p);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -803,20 +817,30 @@ void LedgerConsensus::accept(SHAMap::pointer set)
|
||||
Log(lsTRACE) << "newOL after current ledger transactions";
|
||||
Json::Value p;
|
||||
newOL->addJson(p, LEDGER_JSON_DUMP_TXNS | LEDGER_JSON_DUMP_STATE);
|
||||
ssw.write(std::cerr, p);
|
||||
ssw.write(Log(lsTRACE).ref(), p);
|
||||
Log(lsINFO) << "newLCL after transactions";
|
||||
Json::Value p2;
|
||||
newLCL->addJson(p2, LEDGER_JSON_DUMP_TXNS | LEDGER_JSON_DUMP_STATE);
|
||||
ssw.write(Log(lsTRACE).ref(), p2);
|
||||
}
|
||||
#endif
|
||||
|
||||
SerializedValidation::pointer v = boost::make_shared<SerializedValidation>
|
||||
(newLCLHash, mOurPosition->peekSeed(), true);
|
||||
v->setTrusted();
|
||||
theApp->getValidations().addValidation(v);
|
||||
std::vector<unsigned char> validation = v->getSigned();
|
||||
newcoin::TMValidation val;
|
||||
val.set_validation(&validation[0], validation.size());
|
||||
theApp->getConnectionPool().relayMessage(NULL, boost::make_shared<PackedMessage>(val, newcoin::mtVALIDATION));
|
||||
Log(lsINFO) << "Validation sent " << newLCL->getHash().GetHex();
|
||||
statusChange(newcoin::neACCEPTED_LEDGER, newOL);
|
||||
if (mValidating)
|
||||
{
|
||||
assert (theApp->getOPs().getNetworkTimeNC() > newLCL->getCloseTimeNC());
|
||||
SerializedValidation::pointer v = boost::make_shared<SerializedValidation>
|
||||
(newLCLHash, newLCL->getCloseTimeNC(), mOurPosition->peekSeed(), true);
|
||||
v->setTrusted();
|
||||
// FIXME: If not proposing, set not full
|
||||
theApp->getValidations().addValidation(v);
|
||||
std::vector<unsigned char> validation = v->getSigned();
|
||||
newcoin::TMValidation val;
|
||||
val.set_validation(&validation[0], validation.size());
|
||||
theApp->getConnectionPool().relayMessage(NULL, boost::make_shared<PackedMessage>(val, newcoin::mtVALIDATION));
|
||||
Log(lsINFO) << "Validation sent " << newLCLHash.GetHex();
|
||||
}
|
||||
else Log(lsWARNING) << "Not validating";
|
||||
statusChange(newcoin::neACCEPTED_LEDGER, newLCL);
|
||||
}
|
||||
|
||||
void LedgerConsensus::endConsensus()
|
||||
|
||||
@@ -83,8 +83,11 @@ class LedgerConsensus : public boost::enable_shared_from_this<LedgerConsensus>
|
||||
protected:
|
||||
LCState mState;
|
||||
uint32 mCloseTime;
|
||||
uint256 mPrevLedgerHash;
|
||||
Ledger::pointer mPreviousLedger;
|
||||
LedgerProposal::pointer mOurPosition;
|
||||
NewcoinAddress mValSeed;
|
||||
bool mProposing, mValidating, mHaveCorrectLCL;
|
||||
|
||||
// Convergence tracking, trusted peers indexed by hash of public key
|
||||
boost::unordered_map<uint160, LedgerProposal::pointer> mPeerPositions;
|
||||
@@ -129,7 +132,7 @@ protected:
|
||||
void endConsensus();
|
||||
|
||||
public:
|
||||
LedgerConsensus(Ledger::pointer previousLedger, uint32 closeTime);
|
||||
LedgerConsensus(const uint256& prevLCLHash, Ledger::pointer previousLedger, uint32 closeTime);
|
||||
|
||||
int startup();
|
||||
|
||||
@@ -138,7 +141,7 @@ public:
|
||||
|
||||
SHAMap::pointer getTransactionTree(const uint256& hash, bool doAcquire);
|
||||
TransactionAcquire::pointer getAcquiring(const uint256& hash);
|
||||
void mapComplete(const uint256& hash, SHAMap::pointer map);
|
||||
void mapComplete(const uint256& hash, SHAMap::pointer map, bool acquired);
|
||||
|
||||
void abort();
|
||||
int timerEntry();
|
||||
|
||||
@@ -32,6 +32,7 @@ void LedgerHistory::addAcceptedLedger(Ledger::pointer ledger)
|
||||
uint256 h(ledger->getHash());
|
||||
boost::recursive_mutex::scoped_lock sl(mLedgersByHash.peekMutex());
|
||||
mLedgersByHash.canonicalize(h, ledger);
|
||||
assert(ledger && ledger->isAccepted() && ledger->isImmutable());
|
||||
mLedgersByIndex.insert(std::make_pair(ledger->getLedgerSeq(), ledger));
|
||||
boost::thread thread(boost::bind(&Ledger::saveAcceptedLedger, ledger));
|
||||
thread.detach();
|
||||
@@ -71,6 +72,7 @@ Ledger::pointer LedgerHistory::getLedgerByHash(const uint256& hash)
|
||||
|
||||
Ledger::pointer LedgerHistory::canonicalizeLedger(Ledger::pointer ledger, bool save)
|
||||
{
|
||||
assert(ledger->isImmutable());
|
||||
uint256 h(ledger->getHash());
|
||||
|
||||
if (!save)
|
||||
@@ -83,7 +85,7 @@ Ledger::pointer LedgerHistory::canonicalizeLedger(Ledger::pointer ledger, bool s
|
||||
// save input ledger in map if not in map, otherwise return corresponding map ledger
|
||||
boost::recursive_mutex::scoped_lock sl(mLedgersByHash.peekMutex());
|
||||
mLedgersByHash.canonicalize(h, ledger);
|
||||
if (ledger->isAccepted()) mLedgersByIndex[ledger->getLedgerSeq()]=ledger;
|
||||
if (ledger->isAccepted()) mLedgersByIndex[ledger->getLedgerSeq()] = ledger;
|
||||
return ledger;
|
||||
}
|
||||
// vim:ts=4
|
||||
|
||||
@@ -40,13 +40,14 @@ void LedgerMaster::pushLedger(Ledger::pointer newLCL, Ledger::pointer newOL)
|
||||
assert(newLCL->isClosed() && newLCL->isAccepted());
|
||||
assert(!newOL->isClosed() && !newOL->isAccepted());
|
||||
|
||||
ScopedLock sl(mLock);
|
||||
if (mFinalizedLedger && mFinalizedLedger->isAccepted())
|
||||
if (newLCL->isAccepted())
|
||||
{
|
||||
mLedgerHistory.addAcceptedLedger(mFinalizedLedger);
|
||||
Log(lsINFO) << "StashAccepted: " << mFinalizedLedger->getHash().GetHex();
|
||||
}
|
||||
|
||||
mFinalizedLedger = newLCL;
|
||||
ScopedLock sl(mLock);
|
||||
mCurrentLedger = newOL;
|
||||
mEngine.setLedger(newOL);
|
||||
}
|
||||
|
||||
@@ -28,6 +28,12 @@ LedgerProposal::LedgerProposal(const NewcoinAddress& naSeed, const uint256& prev
|
||||
mPeerID = mPublicKey.getNodeID();
|
||||
}
|
||||
|
||||
LedgerProposal::LedgerProposal(const uint256& prevLgr, const uint256& position) :
|
||||
mPreviousLedger(prevLgr), mCurrentHash(position), mProposeSeq(0)
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
uint256 LedgerProposal::getSigningHash() const
|
||||
{
|
||||
Serializer s(72);
|
||||
|
||||
@@ -32,6 +32,9 @@ public:
|
||||
// our first proposal
|
||||
LedgerProposal(const NewcoinAddress& naSeed, const uint256& prevLedger, const uint256& position);
|
||||
|
||||
// an unsigned proposal
|
||||
LedgerProposal(const uint256& prevLedger, const uint256& position);
|
||||
|
||||
uint256 getSigningHash() const;
|
||||
bool checkSign(const std::string& signature);
|
||||
|
||||
|
||||
29
src/Log.cpp
29
src/Log.cpp
@@ -1,15 +1,15 @@
|
||||
|
||||
#include "Log.h"
|
||||
|
||||
#include <fstream>
|
||||
|
||||
#include <boost/date_time/posix_time/posix_time.hpp>
|
||||
|
||||
boost::recursive_mutex Log::sLock;
|
||||
|
||||
#ifdef DEBUG
|
||||
LogSeverity Log::sMinSeverity = lsTRACE;
|
||||
#else
|
||||
LogSeverity Log::sMinSeverity = lsINFO;
|
||||
#endif
|
||||
|
||||
std::ofstream* Log::outStream = NULL;
|
||||
|
||||
Log::~Log()
|
||||
{
|
||||
@@ -26,9 +26,9 @@ Log::~Log()
|
||||
logMsg += oss.str();
|
||||
boost::recursive_mutex::scoped_lock sl(sLock);
|
||||
if (mSeverity >= sMinSeverity)
|
||||
{
|
||||
std::cerr << logMsg << std::endl;
|
||||
}
|
||||
if (outStream != NULL)
|
||||
(*outStream) << logMsg << std::endl;
|
||||
}
|
||||
|
||||
void Log::setMinSeverity(LogSeverity s)
|
||||
@@ -36,3 +36,20 @@ void Log::setMinSeverity(LogSeverity s)
|
||||
boost::recursive_mutex::scoped_lock sl(sLock);
|
||||
sMinSeverity = s;
|
||||
}
|
||||
|
||||
void Log::setLogFile(boost::filesystem::path path)
|
||||
{
|
||||
std::ofstream* newStream = new std::ofstream(path.c_str(), std::fstream::app);
|
||||
if (!newStream->good())
|
||||
{
|
||||
delete newStream;
|
||||
newStream = NULL;
|
||||
}
|
||||
|
||||
boost::recursive_mutex::scoped_lock sl(sLock);
|
||||
if (outStream != NULL)
|
||||
delete outStream;
|
||||
outStream = newStream;
|
||||
if (outStream)
|
||||
Log(lsINFO) << "Starting up";
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <sstream>
|
||||
|
||||
#include <boost/thread/recursive_mutex.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
enum LogSeverity
|
||||
{
|
||||
@@ -24,6 +25,7 @@ private:
|
||||
protected:
|
||||
static boost::recursive_mutex sLock;
|
||||
static LogSeverity sMinSeverity;
|
||||
static std::ofstream* outStream;
|
||||
|
||||
mutable std::ostringstream oss;
|
||||
LogSeverity mSeverity;
|
||||
@@ -45,6 +47,7 @@ public:
|
||||
}
|
||||
|
||||
static void setMinSeverity(LogSeverity);
|
||||
static void setLogFile(boost::filesystem::path);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -98,6 +98,18 @@ Transaction::pointer NetworkOPs::processTransaction(Transaction::pointer trans,
|
||||
}
|
||||
|
||||
Log(lsDEBUG) << "Status other than success " << r ;
|
||||
if ((mMode != omFULL) && (theApp->suppress(trans->getID())))
|
||||
{
|
||||
newcoin::TMTransaction tx;
|
||||
Serializer s;
|
||||
trans->getSTransaction()->add(s);
|
||||
tx.set_rawtransaction(&s.getData().front(), s.getLength());
|
||||
tx.set_status(newcoin::tsCURRENT);
|
||||
tx.set_receivetimestamp(getNetworkTimeNC());
|
||||
tx.set_ledgerindexpossible(tgtLedger);
|
||||
PackedMessage::pointer packet = boost::make_shared<PackedMessage>(tx, newcoin::mtTRANSACTION);
|
||||
theApp->getConnectionPool().relayMessage(source, packet);
|
||||
}
|
||||
|
||||
trans->setStatus(INVALID);
|
||||
return trans;
|
||||
@@ -234,15 +246,14 @@ RippleState::pointer NetworkOPs::getRippleState(const uint256& uLedger, const ui
|
||||
|
||||
void NetworkOPs::setStateTimer(int sec)
|
||||
{ // set timer early if ledger is closing
|
||||
uint64 consensusTime = mLedgerMaster->getCurrentLedger()->getCloseTimeNC() - LEDGER_WOBBLE_TIME;
|
||||
uint64 now = getNetworkTimeNC();
|
||||
|
||||
if ((mMode == omFULL) && !mConsensus)
|
||||
if (!mConsensus && ((mMode == omFULL) || (mMode == omTRACKING)))
|
||||
{
|
||||
if (now >= consensusTime) sec = 0;
|
||||
uint64 consensusTime = mLedgerMaster->getCurrentLedger()->getCloseTimeNC() - LEDGER_WOBBLE_TIME;
|
||||
uint64 now = getNetworkTimeNC();
|
||||
|
||||
if (now >= consensusTime) sec = 1;
|
||||
else if (sec > (consensusTime - now)) sec = (consensusTime - now);
|
||||
}
|
||||
|
||||
mNetTimer.expires_from_now(boost::posix_time::seconds(sec));
|
||||
mNetTimer.async_wait(boost::bind(&NetworkOPs::checkState, this, boost::asio::placeholders::error));
|
||||
}
|
||||
@@ -250,16 +261,14 @@ void NetworkOPs::setStateTimer(int sec)
|
||||
class ValidationCount
|
||||
{
|
||||
public:
|
||||
int trustedValidations, untrustedValidations, nodesUsing;
|
||||
int trustedValidations, nodesUsing;
|
||||
NewcoinAddress highNode;
|
||||
|
||||
ValidationCount() : trustedValidations(0), untrustedValidations(0), nodesUsing(0) { ; }
|
||||
ValidationCount() : trustedValidations(0), nodesUsing(0) { ; }
|
||||
bool operator>(const ValidationCount& v)
|
||||
{
|
||||
if (trustedValidations > v.trustedValidations) return true;
|
||||
if (trustedValidations < v.trustedValidations) return false;
|
||||
if (untrustedValidations > v.untrustedValidations) return true;
|
||||
if (untrustedValidations < v.untrustedValidations) return false;
|
||||
if (nodesUsing > v.nodesUsing) return true;
|
||||
if (nodesUsing < v.nodesUsing) return false;
|
||||
return highNode > v.highNode;
|
||||
@@ -291,95 +300,18 @@ void NetworkOPs::checkState(const boost::system::error_code& result)
|
||||
Log(lsINFO) << "Node count (" << peerList.size() << ") is sufficient.";
|
||||
}
|
||||
|
||||
// Do we have sufficient validations for our last closed ledger? Or do sufficient nodes
|
||||
// agree? And do we have no better ledger available?
|
||||
// If so, we are either tracking or full.
|
||||
boost::unordered_map<uint256, ValidationCount> ledgers;
|
||||
|
||||
for (std::vector<Peer::pointer>::iterator it = peerList.begin(), end = peerList.end(); it != end; ++it)
|
||||
{
|
||||
if (!*it)
|
||||
{
|
||||
Log(lsDEBUG) << "NOP::CS Dead pointer in peer list";
|
||||
}
|
||||
else
|
||||
{
|
||||
uint256 peerLedger = (*it)->getClosedLedgerHash();
|
||||
if (!!peerLedger)
|
||||
{
|
||||
// FIXME: If we have this ledger, don't count it if it's too far past its close time
|
||||
bool isNew = ledgers.find(peerLedger) == ledgers.end();
|
||||
ValidationCount& vc = ledgers[peerLedger];
|
||||
if (isNew)
|
||||
{
|
||||
theApp->getValidations().getValidationCount(peerLedger,
|
||||
vc.trustedValidations, vc.untrustedValidations);
|
||||
Log(lsTRACE) << peerLedger.GetHex() << " has " << vc.trustedValidations <<
|
||||
" trusted validations and " << vc.untrustedValidations << " untrusted";
|
||||
}
|
||||
if ((vc.nodesUsing == 0) || ((*it)->getNodePublic() > vc.highNode))
|
||||
vc.highNode = (*it)->getNodePublic();
|
||||
++vc.nodesUsing;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ledger::pointer currentClosed = mLedgerMaster->getClosedLedger();
|
||||
uint256 closedLedger = currentClosed->getHash();
|
||||
ValidationCount& vc = ledgers[closedLedger];
|
||||
if ((vc.nodesUsing == 0) || (theApp->getWallet().getNodePublic() > vc.highNode))
|
||||
vc.highNode = theApp->getWallet().getNodePublic();
|
||||
++ledgers[closedLedger].nodesUsing;
|
||||
|
||||
// 3) Is there a network ledger we'd like to switch to? If so, do we have it?
|
||||
bool switchLedgers = false;
|
||||
for(boost::unordered_map<uint256, ValidationCount>::iterator it = ledgers.begin(), end = ledgers.end();
|
||||
it != end; ++it)
|
||||
{
|
||||
if (it->second > vc)
|
||||
{
|
||||
vc = it->second;
|
||||
closedLedger = it->first;
|
||||
switchLedgers = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (mConsensus)
|
||||
{
|
||||
setStateTimer(mConsensus->timerEntry());
|
||||
return;
|
||||
}
|
||||
|
||||
if (switchLedgers)
|
||||
// FIXME: Don't check unless last closed ledger is at least some seconds old
|
||||
// If full or tracking, check only at wobble time!
|
||||
if (checkLastClosedLedger(peerList))
|
||||
{
|
||||
Log(lsWARNING) << "We are not running on the consensus ledger";
|
||||
Log(lsINFO) << "Our LCL " << currentClosed->getHash().GetHex() ;
|
||||
Log(lsINFO) << "Net LCL " << closedLedger.GetHex() ;
|
||||
if ((mMode == omTRACKING) || (mMode == omFULL)) setMode(omTRACKING);
|
||||
Ledger::pointer consensus = mLedgerMaster->getLedgerByHash(closedLedger);
|
||||
if (!consensus)
|
||||
{
|
||||
Log(lsINFO) << "Acquiring consensus ledger";
|
||||
LedgerAcquire::pointer acq = theApp->getMasterLedgerAcquire().findCreate(closedLedger);
|
||||
if (!acq || acq->isFailed())
|
||||
{
|
||||
theApp->getMasterLedgerAcquire().dropLedger(closedLedger);
|
||||
Log(lsERROR) << "Network ledger cannot be acquired";
|
||||
setStateTimer(10);
|
||||
return;
|
||||
}
|
||||
if (!acq->isComplete())
|
||||
{ // add more peers
|
||||
// FIXME: A peer may not have a ledger just because it accepts it as the network's consensus
|
||||
for (std::vector<Peer::pointer>::iterator it = peerList.begin(), end = peerList.end(); it != end; ++it)
|
||||
if ((*it)->getClosedLedgerHash() == closedLedger)
|
||||
acq->peerHas(*it);
|
||||
setStateTimer(5);
|
||||
return;
|
||||
}
|
||||
consensus = acq->getLedger();
|
||||
}
|
||||
switchLastClosedLedger(consensus);
|
||||
setStateTimer(3);
|
||||
return;
|
||||
}
|
||||
|
||||
// WRITEME: Unless we are in omFULL and in the process of doing a consensus,
|
||||
@@ -391,7 +323,7 @@ void NetworkOPs::checkState(const boost::system::error_code& result)
|
||||
if (mMode == omCONNECTED)
|
||||
{ // count number of peers that agree with us and UNL nodes whose validations we have for LCL
|
||||
// if the ledger is good enough, go to omTRACKING - TODO
|
||||
if (!switchLedgers) setMode(omTRACKING);
|
||||
setMode(omTRACKING);
|
||||
}
|
||||
|
||||
if (mMode == omTRACKING)
|
||||
@@ -399,7 +331,11 @@ void NetworkOPs::checkState(const boost::system::error_code& result)
|
||||
// check if the ledger is good enough to go to omFULL
|
||||
// Note: Do not go to omFULL if we don't have the previous ledger
|
||||
// check if the ledger is bad enough to go to omCONNECTED -- TODO
|
||||
if ((!switchLedgers) && theConfig.VALIDATION_SEED.isValid()) setMode(omFULL);
|
||||
if (theApp->getOPs().getNetworkTimeNC() <
|
||||
(theApp->getMasterLedger().getCurrentLedger()->getCloseTimeNC() + 4))
|
||||
setMode(omFULL);
|
||||
else
|
||||
Log(lsWARNING) << "Too late to go to full, will try in consensus window";
|
||||
}
|
||||
|
||||
if (mMode == omFULL)
|
||||
@@ -413,7 +349,102 @@ void NetworkOPs::checkState(const boost::system::error_code& result)
|
||||
beginConsensus(theApp->getMasterLedger().getCurrentLedger());
|
||||
if (mConsensus)
|
||||
setStateTimer(mConsensus->timerEntry());
|
||||
else setStateTimer(10);
|
||||
else setStateTimer(4);
|
||||
}
|
||||
|
||||
bool NetworkOPs::checkLastClosedLedger(const std::vector<Peer::pointer>& peerList)
|
||||
{ // Returns true if there's an *abnormal* ledger issue, normal changing in TRACKING mode should return false
|
||||
// Do we have sufficient validations for our last closed ledger? Or do sufficient nodes
|
||||
// agree? And do we have no better ledger available?
|
||||
// If so, we are either tracking or full.
|
||||
|
||||
// FIXME: We may have a ledger with many recent validations but that no directly-connected
|
||||
// node is using. THis is kind of fundamental.
|
||||
|
||||
boost::unordered_map<uint256, ValidationCount> ledgers;
|
||||
|
||||
{
|
||||
boost::unordered_map<uint256, int> current = theApp->getValidations().getCurrentValidations();
|
||||
for (boost::unordered_map<uint256, int>::iterator it = current.begin(), end = current.end(); it != end; ++it)
|
||||
ledgers[it->first].trustedValidations += it->second;
|
||||
}
|
||||
|
||||
Ledger::pointer currentClosed = mLedgerMaster->getClosedLedger();
|
||||
uint256 closedLedger = currentClosed->getHash();
|
||||
ValidationCount& ourVC = ledgers[closedLedger];
|
||||
++ourVC.nodesUsing;
|
||||
ourVC.highNode = theApp->getWallet().getNodePublic();
|
||||
|
||||
for (std::vector<Peer::pointer>::const_iterator it = peerList.begin(), end = peerList.end(); it != end; ++it)
|
||||
{
|
||||
if (!*it)
|
||||
{
|
||||
Log(lsDEBUG) << "NOP::CS Dead pointer in peer list";
|
||||
}
|
||||
else if ((*it)->isConnected())
|
||||
{
|
||||
uint256 peerLedger = (*it)->getClosedLedgerHash();
|
||||
if (!!peerLedger)
|
||||
{
|
||||
ValidationCount& vc = ledgers[peerLedger];
|
||||
if ((vc.nodesUsing == 0) || ((*it)->getNodePublic() > vc.highNode))
|
||||
vc.highNode = (*it)->getNodePublic();
|
||||
++vc.nodesUsing;
|
||||
}
|
||||
else Log(lsTRACE) << "Connected peer announces no LCL";
|
||||
}
|
||||
}
|
||||
|
||||
ValidationCount bestVC = ledgers[closedLedger];
|
||||
|
||||
// 3) Is there a network ledger we'd like to switch to? If so, do we have it?
|
||||
bool switchLedgers = false;
|
||||
for(boost::unordered_map<uint256, ValidationCount>::iterator it = ledgers.begin(), end = ledgers.end();
|
||||
it != end; ++it)
|
||||
{
|
||||
Log(lsTRACE) << "L: " << it->first.GetHex() <<
|
||||
" t=" << it->second.trustedValidations << ", n=" << it->second.nodesUsing;
|
||||
if (it->second > bestVC)
|
||||
{
|
||||
bestVC = it->second;
|
||||
closedLedger = it->first;
|
||||
switchLedgers = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!switchLedgers)
|
||||
return false;
|
||||
|
||||
Log(lsWARNING) << "We are not running on the consensus ledger";
|
||||
Log(lsINFO) << "Our LCL " << currentClosed->getHash().GetHex();
|
||||
Log(lsINFO) << "Net LCL " << closedLedger.GetHex();
|
||||
if ((mMode == omTRACKING) || (mMode == omFULL)) setMode(omCONNECTED);
|
||||
Ledger::pointer consensus = mLedgerMaster->getLedgerByHash(closedLedger);
|
||||
if (!consensus)
|
||||
{
|
||||
Log(lsINFO) << "Acquiring consensus ledger";
|
||||
LedgerAcquire::pointer acq = theApp->getMasterLedgerAcquire().findCreate(closedLedger);
|
||||
if (!acq || acq->isFailed())
|
||||
{
|
||||
theApp->getMasterLedgerAcquire().dropLedger(closedLedger);
|
||||
Log(lsERROR) << "Network ledger cannot be acquired";
|
||||
return true;
|
||||
}
|
||||
if (!acq->isComplete())
|
||||
{ // add more peers
|
||||
// FIXME: A peer may not have a ledger just because it accepts it as the network's consensus
|
||||
for (std::vector<Peer::pointer>::const_iterator it = peerList.begin(), end = peerList.end();
|
||||
it != end; ++it)
|
||||
{
|
||||
if ((*it)->getClosedLedgerHash() == closedLedger)
|
||||
acq->peerHas(*it);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
consensus = acq->getLedger();
|
||||
}
|
||||
switchLastClosedLedger(consensus);
|
||||
return true;
|
||||
}
|
||||
|
||||
void NetworkOPs::switchLastClosedLedger(Ledger::pointer newLedger)
|
||||
@@ -431,12 +462,17 @@ void NetworkOPs::switchLastClosedLedger(Ledger::pointer newLedger)
|
||||
Ledger::pointer openLedger = boost::make_shared<Ledger>(false, boost::ref(*newLedger));
|
||||
mLedgerMaster->switchLedgers(newLedger, openLedger);
|
||||
|
||||
if (getNetworkTimeNC() > openLedger->getCloseTimeNC())
|
||||
{ // this ledger has already closed
|
||||
}
|
||||
|
||||
newcoin::TMStatusChange s;
|
||||
s.set_newevent(newcoin::neSWITCHED_LEDGER);
|
||||
s.set_ledgerseq(newLedger->getLedgerSeq());
|
||||
s.set_networktime(theApp->getOPs().getNetworkTimeNC());
|
||||
uint256 hash = newLedger->getParentHash();
|
||||
s.set_previousledgerhash(hash.begin(), hash.size());
|
||||
hash = newLedger->getHash();
|
||||
s.set_ledgerhash(hash.begin(), hash.size());
|
||||
PackedMessage::pointer packet = boost::make_shared<PackedMessage>(s, newcoin::mtSTATUS_CHANGE);
|
||||
theApp->getConnectionPool().relayMessage(NULL, packet);
|
||||
}
|
||||
// vim:ts=4
|
||||
|
||||
int NetworkOPs::beginConsensus(Ledger::pointer closingLedger)
|
||||
{
|
||||
@@ -456,8 +492,9 @@ int NetworkOPs::beginConsensus(Ledger::pointer closingLedger)
|
||||
// Create a consensus object to get consensus on this ledger
|
||||
if (!!mConsensus) mConsensus->abort();
|
||||
prevLedger->setImmutable();
|
||||
mConsensus = boost::make_shared<LedgerConsensus>
|
||||
(prevLedger, theApp->getMasterLedger().getCurrentLedger()->getCloseTimeNC());
|
||||
mConsensus = boost::make_shared<LedgerConsensus>(
|
||||
prevLedger->getHash(), // FIXME: Only do this if the previous ledger is the consensus previous ledger
|
||||
prevLedger, theApp->getMasterLedger().getCurrentLedger()->getCloseTimeNC());
|
||||
|
||||
Log(lsDEBUG) << "Pre-close time, initiating consensus engine";
|
||||
return mConsensus->startup();
|
||||
@@ -471,10 +508,11 @@ bool NetworkOPs::recvPropose(uint32 proposeSeq, const uint256& proposeHash,
|
||||
// XXX Take a vuc for pubkey.
|
||||
NewcoinAddress naPeerPublic = NewcoinAddress::createNodePublic(strCopy(pubKey));
|
||||
|
||||
if (mMode != omFULL) // FIXME: Should we relay?
|
||||
if (mMode != omFULL)
|
||||
{
|
||||
Log(lsWARNING) << "Received proposal when not full: " << mMode;
|
||||
return true;
|
||||
Log(lsINFO) << "Received proposal when not full: " << mMode;
|
||||
Serializer s(signature);
|
||||
return theApp->suppress(s.getSHA512Half());
|
||||
}
|
||||
if (!mConsensus)
|
||||
{
|
||||
@@ -527,17 +565,34 @@ bool NetworkOPs::hasTXSet(boost::shared_ptr<Peer> peer, const uint256& set, newc
|
||||
void NetworkOPs::mapComplete(const uint256& hash, SHAMap::pointer map)
|
||||
{
|
||||
if (mConsensus)
|
||||
mConsensus->mapComplete(hash, map);
|
||||
mConsensus->mapComplete(hash, map, true);
|
||||
}
|
||||
|
||||
void NetworkOPs::endConsensus()
|
||||
{
|
||||
uint256 deadLedger = theApp->getMasterLedger().getClosedLedger()->getParentHash();
|
||||
Log(lsTRACE) << "Ledger " << deadLedger.GetHex() << " is now dead";
|
||||
std::vector<Peer::pointer> peerList = theApp->getConnectionPool().getPeerVector();
|
||||
for (std::vector<Peer::pointer>::const_iterator it = peerList.begin(), end = peerList.end(); it != end; ++it)
|
||||
if (*it && ((*it)->getClosedLedgerHash() == deadLedger))
|
||||
{
|
||||
Log(lsTRACE) << "Killing obsolete peer status";
|
||||
(*it)->cycleStatus();
|
||||
}
|
||||
mConsensus = boost::shared_ptr<LedgerConsensus>();
|
||||
}
|
||||
|
||||
void NetworkOPs::setMode(OperatingMode om)
|
||||
{
|
||||
if (mMode == om) return;
|
||||
if (mMode == omFULL)
|
||||
{
|
||||
if (mConsensus)
|
||||
{
|
||||
mConsensus->abort();
|
||||
mConsensus = boost::shared_ptr<LedgerConsensus>();
|
||||
}
|
||||
}
|
||||
Log l((om < mMode) ? lsWARNING : lsINFO);
|
||||
if (om == omDISCONNECTED) l << "STATE->Disonnected";
|
||||
else if (om == omCONNECTED) l << "STATE->Connected";
|
||||
@@ -574,4 +629,23 @@ bool NetworkOPs::recvValidation(SerializedValidation::pointer val)
|
||||
return theApp->getValidations().addValidation(val);
|
||||
}
|
||||
|
||||
Json::Value NetworkOPs::getServerInfo()
|
||||
{
|
||||
Json::Value info = Json::objectValue;
|
||||
|
||||
switch (mMode)
|
||||
{
|
||||
case omDISCONNECTED: info["serverState"] = "disconnected"; break;
|
||||
case omCONNECTED: info["serverState"] = "connected"; break;
|
||||
case omTRACKING: info["serverState"] = "tracking"; break;
|
||||
case omFULL: info["serverState"] = "validating"; break;
|
||||
default: info["serverState"] = "unknown";
|
||||
}
|
||||
|
||||
if (!theConfig.VALIDATION_SEED.isValid()) info["serverState"] = "none";
|
||||
else info["validationPKey"] = NewcoinAddress::createNodePublic(theConfig.VALIDATION_SEED).humanNodePublic();
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
// vim:ts=4
|
||||
|
||||
@@ -124,9 +124,11 @@ public:
|
||||
// network state machine
|
||||
void checkState(const boost::system::error_code& result);
|
||||
void switchLastClosedLedger(Ledger::pointer newLedger); // Used for the "jump" case
|
||||
bool checkLastClosedLedger(const std::vector<Peer::pointer> &);
|
||||
int beginConsensus(Ledger::pointer closingLedger);
|
||||
void endConsensus();
|
||||
void setStateTimer(int seconds);
|
||||
Json::Value getServerInfo();
|
||||
|
||||
// client information retrieval functions
|
||||
std::vector< std::pair<uint32, uint256> >
|
||||
|
||||
@@ -716,7 +716,9 @@ bool NewcoinAddress::setSeedGeneric(const std::string& strText)
|
||||
if (strText.empty()
|
||||
|| naTemp.setAccountID(strText)
|
||||
|| naTemp.setAccountPublic(strText)
|
||||
|| naTemp.setAccountPrivate(strText))
|
||||
|| naTemp.setAccountPrivate(strText)
|
||||
|| naTemp.setNodePublic(strText)
|
||||
|| naTemp.setNodePrivate(strText))
|
||||
{
|
||||
bResult = false;
|
||||
}
|
||||
|
||||
410
src/Peer.cpp
410
src/Peer.cpp
@@ -23,33 +23,39 @@
|
||||
#define NODE_VERIFY_SECONDS 15
|
||||
|
||||
Peer::Peer(boost::asio::io_service& io_service, boost::asio::ssl::context& ctx) :
|
||||
mConnected(false),
|
||||
mHelloed(false),
|
||||
mDetaching(false),
|
||||
mSocketSsl(io_service, ctx),
|
||||
mVerifyTimer(io_service)
|
||||
{
|
||||
// Log(lsDEBUG) << "CREATING PEER: " << ADDRESS(this);
|
||||
}
|
||||
|
||||
void Peer::handle_write(const boost::system::error_code& error, size_t bytes_transferred)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
if(error)
|
||||
std::cerr << "Peer::handle_write Error: " << error << " bytes: " << bytes_transferred << std::endl;
|
||||
// else
|
||||
// if (!error)
|
||||
// std::cerr << "Peer::handle_write bytes: "<< bytes_transferred << std::endl;
|
||||
#endif
|
||||
|
||||
mSendingPacket = PackedMessage::pointer();
|
||||
|
||||
if (error)
|
||||
if (mDetaching)
|
||||
{
|
||||
detach("hw");
|
||||
return;
|
||||
// Ignore write requests when detatching.
|
||||
nothing();
|
||||
}
|
||||
else if (error)
|
||||
{
|
||||
Log(lsINFO) << "Peer: Write: Error: " << ADDRESS(this) << ": bytes=" << bytes_transferred << ": " << error.category().name() << ": " << error.message() << ": " << error;
|
||||
|
||||
if (!mSendQ.empty())
|
||||
detach("hw");
|
||||
}
|
||||
else if (!mSendQ.empty())
|
||||
{
|
||||
PackedMessage::pointer packet = mSendQ.front();
|
||||
if(packet)
|
||||
|
||||
if (packet)
|
||||
{
|
||||
sendPacketForce(packet);
|
||||
mSendQ.pop_front();
|
||||
@@ -57,25 +63,51 @@ void Peer::handle_write(const boost::system::error_code& error, size_t bytes_tra
|
||||
}
|
||||
}
|
||||
|
||||
void Peer::setIpPort(const std::string& strIP, int iPort)
|
||||
{
|
||||
mIpPort = make_pair(strIP, iPort);
|
||||
|
||||
Log(lsDEBUG) << "Peer: Set: "
|
||||
<< ADDRESS(this) << "> "
|
||||
<< (mNodePublic.isValid() ? mNodePublic.humanNodePublic() : "-") << " " << getIP() << " " << getPort();
|
||||
}
|
||||
|
||||
void Peer::detach(const char *rsn)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
std::cerr << "DETACHING PEER: " << rsn << std::endl;
|
||||
#endif
|
||||
boost::system::error_code ecCancel;
|
||||
|
||||
(void) mVerifyTimer.cancel();
|
||||
|
||||
mSendQ.clear();
|
||||
|
||||
if (!mIpPort.first.empty())
|
||||
if (!mDetaching)
|
||||
{
|
||||
if (mClientConnect)
|
||||
// Connection might be part of scanning. Inform connect failed.
|
||||
theApp->getConnectionPool().peerFailed(mIpPort.first, mIpPort.second);
|
||||
mDetaching = true; // Race is ok.
|
||||
|
||||
theApp->getConnectionPool().peerDisconnected(shared_from_this(), mIpPort, mNodePublic);
|
||||
mIpPort.first.clear();
|
||||
Log(lsDEBUG) << "Peer: Detach: "
|
||||
<< ADDRESS(this) << "> "
|
||||
<< rsn << ": "
|
||||
<< (mNodePublic.isValid() ? mNodePublic.humanNodePublic() : "-") << " " << getIP() << " " << getPort();
|
||||
|
||||
mSendQ.clear();
|
||||
|
||||
(void) mVerifyTimer.cancel();
|
||||
mSocketSsl.async_shutdown(boost::bind(&Peer::handleShutdown, shared_from_this(), boost::asio::placeholders::error));
|
||||
|
||||
if (mNodePublic.isValid())
|
||||
{
|
||||
theApp->getConnectionPool().peerDisconnected(shared_from_this(), mNodePublic);
|
||||
|
||||
mNodePublic.clear(); // Be idompotent.
|
||||
}
|
||||
|
||||
if (!mIpPort.first.empty())
|
||||
{
|
||||
// Connection might be part of scanning. Inform connect failed.
|
||||
// Might need to scan. Inform connection closed.
|
||||
theApp->getConnectionPool().peerClosed(shared_from_this(), mIpPort.first, mIpPort.second);
|
||||
|
||||
mIpPort.first.clear(); // Be idompotent.
|
||||
}
|
||||
|
||||
Log(lsDEBUG) << "Peer: Detach: "
|
||||
<< ADDRESS(this) << "< "
|
||||
<< rsn << ": "
|
||||
<< (mNodePublic.isValid() ? mNodePublic.humanNodePublic() : "-") << " " << getIP() << " " << getPort();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,14 +122,15 @@ void Peer::handleVerifyTimer(const boost::system::error_code& ecResult)
|
||||
}
|
||||
else if (ecResult)
|
||||
{
|
||||
std::cerr << "Peer verify timer error: " << std::endl;
|
||||
Log(lsINFO) << "Peer verify timer error";
|
||||
|
||||
// Can't do anything sound.
|
||||
abort();
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "Peer failed to verify in time." << std::endl;
|
||||
Log(lsINFO) << "Peer: Verify: Peer failed to verify in time.";
|
||||
|
||||
detach("hvt");
|
||||
}
|
||||
}
|
||||
@@ -110,8 +143,8 @@ void Peer::connect(const std::string strIp, int iPort)
|
||||
|
||||
mClientConnect = true;
|
||||
|
||||
std::cerr << "Peer::connect: " << strIp << " " << iPort << std::endl;
|
||||
mIpPort = make_pair(strIp, iPort);
|
||||
mIpPort = make_pair(strIp, iPort);
|
||||
mIpPortConnect = mIpPort;
|
||||
assert(!mIpPort.first.empty());
|
||||
|
||||
boost::asio::ip::tcp::resolver::query query(strIp, boost::lexical_cast<std::string>(iPortAct),
|
||||
@@ -122,7 +155,7 @@ void Peer::connect(const std::string strIp, int iPort)
|
||||
|
||||
if (err || itrEndpoint == boost::asio::ip::tcp::resolver::iterator())
|
||||
{
|
||||
std::cerr << "Peer::connect: Bad IP" << std::endl;
|
||||
Log(lsWARNING) << "Peer: Connect: Bad IP: " << strIp;
|
||||
detach("c");
|
||||
return;
|
||||
}
|
||||
@@ -133,7 +166,7 @@ void Peer::connect(const std::string strIp, int iPort)
|
||||
|
||||
if (err)
|
||||
{
|
||||
std::cerr << "Peer::connect: Failed to set timer." << std::endl;
|
||||
Log(lsWARNING) << "Peer: Connect: Failed to set timer.";
|
||||
detach("c2");
|
||||
return;
|
||||
}
|
||||
@@ -141,10 +174,10 @@ void Peer::connect(const std::string strIp, int iPort)
|
||||
|
||||
if (!err)
|
||||
{
|
||||
std::cerr << "Peer::connect: Connecting: " << mIpPort.first << " " << mIpPort.second << std::endl;
|
||||
Log(lsINFO) << "Peer: Connect: Outbound: " << ADDRESS(this) << ": " << mIpPort.first << " " << mIpPort.second;
|
||||
|
||||
boost::asio::async_connect(
|
||||
mSocketSsl.lowest_layer(),
|
||||
getSocket(),
|
||||
itrEndpoint,
|
||||
boost::bind(
|
||||
&Peer::handleConnect,
|
||||
@@ -162,7 +195,7 @@ void Peer::handleStart(const boost::system::error_code& error)
|
||||
{
|
||||
if (error)
|
||||
{
|
||||
std::cerr << "Peer::handleStart: failed:" << error << std::endl;
|
||||
Log(lsINFO) << "Peer: Handshake: Error: " << error.category().name() << ": " << error.message() << ": " << error;
|
||||
detach("hs");
|
||||
}
|
||||
else
|
||||
@@ -177,7 +210,7 @@ void Peer::handleConnect(const boost::system::error_code& error, boost::asio::ip
|
||||
{
|
||||
if (error)
|
||||
{
|
||||
std::cerr << "Connect peer: failed:" << error << std::endl;
|
||||
Log(lsINFO) << "Peer: Connect: Error: " << error.category().name() << ": " << error.message() << ": " << error;
|
||||
detach("hc");
|
||||
}
|
||||
else
|
||||
@@ -191,59 +224,57 @@ void Peer::handleConnect(const boost::system::error_code& error, boost::asio::ip
|
||||
}
|
||||
}
|
||||
|
||||
// Connect ssl as server.
|
||||
// Connect ssl as server to an inbound connection.
|
||||
// - We don't bother remembering the inbound IP or port. Only useful for debugging.
|
||||
void Peer::connected(const boost::system::error_code& error)
|
||||
{
|
||||
boost::asio::ip::tcp::endpoint ep = mSocketSsl.lowest_layer().remote_endpoint();
|
||||
boost::asio::ip::tcp::endpoint ep = getSocket().remote_endpoint();
|
||||
int iPort = ep.port();
|
||||
std::string strIp = ep.address().to_string();
|
||||
|
||||
mClientConnect = false;
|
||||
mIpPortConnect = make_pair(strIp, iPort);
|
||||
|
||||
if (iPort == SYSTEM_PEER_PORT) //TODO: Why are you doing this?
|
||||
iPort = -1;
|
||||
|
||||
if (error)
|
||||
if (!error)
|
||||
{
|
||||
std::cerr << "Remote peer: accept error: " << strIp << " " << iPort << " : " << error << std::endl;
|
||||
detach("ctd");
|
||||
}
|
||||
else if (!theApp->getConnectionPool().peerRegister(shared_from_this(), strIp, iPort))
|
||||
{
|
||||
std::cerr << "Remote peer: rejecting: " << strIp << " " << iPort << std::endl;
|
||||
// XXX Reject with a rejection message: already connected
|
||||
detach("ctd2");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Not redundant ip and port, add to connection list.
|
||||
// Not redundant ip and port, handshake, and start.
|
||||
|
||||
std::cerr << "Remote peer: accepted: " << strIp << " " << iPort << std::endl;
|
||||
|
||||
mIpPort = make_pair(strIp, iPort);
|
||||
assert(!mIpPort.first.empty());
|
||||
Log(lsINFO) << "Peer: Inbound: Accepted: " << ADDRESS(this) << ": " << strIp << " " << iPort;
|
||||
|
||||
mSocketSsl.set_verify_mode(boost::asio::ssl::verify_none);
|
||||
|
||||
mSocketSsl.async_handshake(boost::asio::ssl::stream<boost::asio::ip::tcp::socket>::server,
|
||||
boost::bind(&Peer::handleStart, shared_from_this(), boost::asio::placeholders::error));
|
||||
}
|
||||
else if (!mDetaching)
|
||||
{
|
||||
Log(lsINFO) << "Peer: Inbound: Error: " << ADDRESS(this) << ": " << strIp << " " << iPort << " : " << error.category().name() << ": " << error.message() << ": " << error;
|
||||
|
||||
detach("ctd");
|
||||
}
|
||||
}
|
||||
|
||||
void Peer::sendPacketForce(PackedMessage::pointer packet)
|
||||
{
|
||||
mSendingPacket = packet;
|
||||
boost::asio::async_write(mSocketSsl, boost::asio::buffer(packet->getBuffer()),
|
||||
boost::bind(&Peer::handle_write, shared_from_this(),
|
||||
boost::asio::placeholders::error,
|
||||
boost::asio::placeholders::bytes_transferred));
|
||||
if (!mDetaching)
|
||||
{
|
||||
mSendingPacket = packet;
|
||||
|
||||
boost::asio::async_write(mSocketSsl, boost::asio::buffer(packet->getBuffer()),
|
||||
boost::bind(&Peer::handle_write, shared_from_this(),
|
||||
boost::asio::placeholders::error,
|
||||
boost::asio::placeholders::bytes_transferred));
|
||||
}
|
||||
}
|
||||
|
||||
void Peer::sendPacket(PackedMessage::pointer packet)
|
||||
{
|
||||
if(packet)
|
||||
if (packet)
|
||||
{
|
||||
if(mSendingPacket)
|
||||
if (mSendingPacket)
|
||||
{
|
||||
mSendQ.push_back(packet);
|
||||
}
|
||||
@@ -256,10 +287,14 @@ void Peer::sendPacket(PackedMessage::pointer packet)
|
||||
|
||||
void Peer::start_read_header()
|
||||
{
|
||||
mReadbuf.clear();
|
||||
mReadbuf.resize(HEADER_SIZE);
|
||||
boost::asio::async_read(mSocketSsl, boost::asio::buffer(mReadbuf),
|
||||
boost::bind(&Peer::handle_read_header, shared_from_this(), boost::asio::placeholders::error));
|
||||
if (!mDetaching)
|
||||
{
|
||||
mReadbuf.clear();
|
||||
mReadbuf.resize(HEADER_SIZE);
|
||||
|
||||
boost::asio::async_read(mSocketSsl, boost::asio::buffer(mReadbuf),
|
||||
boost::bind(&Peer::handle_read_header, shared_from_this(), boost::asio::placeholders::error));
|
||||
}
|
||||
}
|
||||
|
||||
void Peer::start_read_body(unsigned msg_len)
|
||||
@@ -267,19 +302,28 @@ void Peer::start_read_body(unsigned msg_len)
|
||||
// m_readbuf already contains the header in its first HEADER_SIZE
|
||||
// bytes. Expand it to fit in the body as well, and start async
|
||||
// read into the body.
|
||||
//
|
||||
mReadbuf.resize(HEADER_SIZE + msg_len);
|
||||
boost::asio::async_read(mSocketSsl, boost::asio::buffer(&mReadbuf[HEADER_SIZE], msg_len),
|
||||
boost::bind(&Peer::handle_read_body, shared_from_this(), boost::asio::placeholders::error));
|
||||
|
||||
if (!mDetaching)
|
||||
{
|
||||
mReadbuf.resize(HEADER_SIZE + msg_len);
|
||||
|
||||
boost::asio::async_read(mSocketSsl, boost::asio::buffer(&mReadbuf[HEADER_SIZE], msg_len),
|
||||
boost::bind(&Peer::handle_read_body, shared_from_this(), boost::asio::placeholders::error));
|
||||
}
|
||||
}
|
||||
|
||||
void Peer::handle_read_header(const boost::system::error_code& error)
|
||||
{
|
||||
if (!error)
|
||||
if (mDetaching)
|
||||
{
|
||||
// Drop data or error if detaching.
|
||||
nothing();
|
||||
}
|
||||
else if (!error)
|
||||
{
|
||||
unsigned msg_len = PackedMessage::getLength(mReadbuf);
|
||||
// WRITEME: Compare to maximum message length, abort if too large
|
||||
if(msg_len>(32*1024*1024))
|
||||
if (msg_len>(32*1024*1024))
|
||||
{
|
||||
detach("hrh");
|
||||
return;
|
||||
@@ -288,26 +332,30 @@ void Peer::handle_read_header(const boost::system::error_code& error)
|
||||
}
|
||||
else
|
||||
{
|
||||
Log(lsINFO) << "Peer: Header: Error: " << ADDRESS(this) << ": " << error.category().name() << ": " << error.message() << ": " << error;
|
||||
detach("hrh2");
|
||||
std::cerr << "Peer::handle_read_header: Error: " << error << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void Peer::handle_read_body(const boost::system::error_code& error)
|
||||
{
|
||||
if (!error)
|
||||
if (mDetaching)
|
||||
{
|
||||
// Drop data or error if detaching.
|
||||
nothing();
|
||||
}
|
||||
else if (!error)
|
||||
{
|
||||
processReadBuffer();
|
||||
start_read_header();
|
||||
}
|
||||
else
|
||||
{
|
||||
Log(lsINFO) << "Peer: Body: Error: " << ADDRESS(this) << ": " << error.category().name() << ": " << error.message() << ": " << error;
|
||||
detach("hrb");
|
||||
std::cerr << "Peer::handle_read_body: Error: " << error << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Peer::processReadBuffer()
|
||||
{
|
||||
int type = PackedMessage::getType(mReadbuf);
|
||||
@@ -318,9 +366,9 @@ void Peer::processReadBuffer()
|
||||
// std::cerr << "Peer::processReadBuffer: " << mIpPort.first << " " << mIpPort.second << std::endl;
|
||||
|
||||
// If connected and get a mtHELLO or if not connected and get a non-mtHELLO, wrong message was sent.
|
||||
if (mConnected == (type == newcoin::mtHELLO))
|
||||
if (mHelloed == (type == newcoin::mtHELLO))
|
||||
{
|
||||
std::cerr << "Wrong message type: " << type << std::endl;
|
||||
Log(lsWARNING) << "Wrong message type: " << type;
|
||||
detach("prb1");
|
||||
}
|
||||
else
|
||||
@@ -330,7 +378,7 @@ void Peer::processReadBuffer()
|
||||
case newcoin::mtHELLO:
|
||||
{
|
||||
newcoin::TMHello msg;
|
||||
if(msg.ParseFromArray(&mReadbuf[HEADER_SIZE], mReadbuf.size() - HEADER_SIZE))
|
||||
if (msg.ParseFromArray(&mReadbuf[HEADER_SIZE], mReadbuf.size() - HEADER_SIZE))
|
||||
recvHello(msg);
|
||||
else std::cerr << "parse error: " << type << std::endl;
|
||||
}
|
||||
@@ -339,7 +387,7 @@ void Peer::processReadBuffer()
|
||||
case newcoin::mtERROR_MSG:
|
||||
{
|
||||
newcoin::TMErrorMsg msg;
|
||||
if(msg.ParseFromArray(&mReadbuf[HEADER_SIZE], mReadbuf.size() - HEADER_SIZE))
|
||||
if (msg.ParseFromArray(&mReadbuf[HEADER_SIZE], mReadbuf.size() - HEADER_SIZE))
|
||||
recvErrorMessage(msg);
|
||||
else std::cerr << "parse error: " << type << std::endl;
|
||||
}
|
||||
@@ -348,7 +396,7 @@ void Peer::processReadBuffer()
|
||||
case newcoin::mtPING:
|
||||
{
|
||||
newcoin::TMPing msg;
|
||||
if(msg.ParseFromArray(&mReadbuf[HEADER_SIZE], mReadbuf.size() - HEADER_SIZE))
|
||||
if (msg.ParseFromArray(&mReadbuf[HEADER_SIZE], mReadbuf.size() - HEADER_SIZE))
|
||||
recvPing(msg);
|
||||
else std::cerr << "parse error: " << type << std::endl;
|
||||
}
|
||||
@@ -357,7 +405,7 @@ void Peer::processReadBuffer()
|
||||
case newcoin::mtGET_CONTACTS:
|
||||
{
|
||||
newcoin::TMGetContacts msg;
|
||||
if(msg.ParseFromArray(&mReadbuf[HEADER_SIZE], mReadbuf.size() - HEADER_SIZE))
|
||||
if (msg.ParseFromArray(&mReadbuf[HEADER_SIZE], mReadbuf.size() - HEADER_SIZE))
|
||||
recvGetContacts(msg);
|
||||
else std::cerr << "parse error: " << type << std::endl;
|
||||
}
|
||||
@@ -366,7 +414,7 @@ void Peer::processReadBuffer()
|
||||
case newcoin::mtCONTACT:
|
||||
{
|
||||
newcoin::TMContact msg;
|
||||
if(msg.ParseFromArray(&mReadbuf[HEADER_SIZE], mReadbuf.size() - HEADER_SIZE))
|
||||
if (msg.ParseFromArray(&mReadbuf[HEADER_SIZE], mReadbuf.size() - HEADER_SIZE))
|
||||
recvContact(msg);
|
||||
else std::cerr << "parse error: " << type << std::endl;
|
||||
}
|
||||
@@ -374,7 +422,7 @@ void Peer::processReadBuffer()
|
||||
case newcoin::mtGET_PEERS:
|
||||
{
|
||||
newcoin::TMGetPeers msg;
|
||||
if(msg.ParseFromArray(&mReadbuf[HEADER_SIZE], mReadbuf.size() - HEADER_SIZE))
|
||||
if (msg.ParseFromArray(&mReadbuf[HEADER_SIZE], mReadbuf.size() - HEADER_SIZE))
|
||||
recvGetPeers(msg);
|
||||
else std::cerr << "parse error: " << type << std::endl;
|
||||
}
|
||||
@@ -382,7 +430,7 @@ void Peer::processReadBuffer()
|
||||
case newcoin::mtPEERS:
|
||||
{
|
||||
newcoin::TMPeers msg;
|
||||
if(msg.ParseFromArray(&mReadbuf[HEADER_SIZE], mReadbuf.size() - HEADER_SIZE))
|
||||
if (msg.ParseFromArray(&mReadbuf[HEADER_SIZE], mReadbuf.size() - HEADER_SIZE))
|
||||
recvPeers(msg);
|
||||
else std::cerr << "parse error: " << type << std::endl;
|
||||
}
|
||||
@@ -391,7 +439,7 @@ void Peer::processReadBuffer()
|
||||
case newcoin::mtSEARCH_TRANSACTION:
|
||||
{
|
||||
newcoin::TMSearchTransaction msg;
|
||||
if(msg.ParseFromArray(&mReadbuf[HEADER_SIZE], mReadbuf.size() - HEADER_SIZE))
|
||||
if (msg.ParseFromArray(&mReadbuf[HEADER_SIZE], mReadbuf.size() - HEADER_SIZE))
|
||||
recvSearchTransaction(msg);
|
||||
else std::cerr << "parse error: " << type << std::endl;
|
||||
}
|
||||
@@ -400,7 +448,7 @@ void Peer::processReadBuffer()
|
||||
case newcoin::mtGET_ACCOUNT:
|
||||
{
|
||||
newcoin::TMGetAccount msg;
|
||||
if(msg.ParseFromArray(&mReadbuf[HEADER_SIZE], mReadbuf.size() - HEADER_SIZE))
|
||||
if (msg.ParseFromArray(&mReadbuf[HEADER_SIZE], mReadbuf.size() - HEADER_SIZE))
|
||||
recvGetAccount(msg);
|
||||
else std::cerr << "parse error: " << type << std::endl;
|
||||
}
|
||||
@@ -409,7 +457,7 @@ void Peer::processReadBuffer()
|
||||
case newcoin::mtACCOUNT:
|
||||
{
|
||||
newcoin::TMAccount msg;
|
||||
if(msg.ParseFromArray(&mReadbuf[HEADER_SIZE], mReadbuf.size() - HEADER_SIZE))
|
||||
if (msg.ParseFromArray(&mReadbuf[HEADER_SIZE], mReadbuf.size() - HEADER_SIZE))
|
||||
recvAccount(msg);
|
||||
else std::cerr << "parse error: " << type << std::endl;
|
||||
}
|
||||
@@ -418,7 +466,7 @@ void Peer::processReadBuffer()
|
||||
case newcoin::mtTRANSACTION:
|
||||
{
|
||||
newcoin::TMTransaction msg;
|
||||
if(msg.ParseFromArray(&mReadbuf[HEADER_SIZE], mReadbuf.size() - HEADER_SIZE))
|
||||
if (msg.ParseFromArray(&mReadbuf[HEADER_SIZE], mReadbuf.size() - HEADER_SIZE))
|
||||
recvTransaction(msg);
|
||||
else std::cerr << "parse error: " << type << std::endl;
|
||||
}
|
||||
@@ -427,7 +475,7 @@ void Peer::processReadBuffer()
|
||||
case newcoin::mtSTATUS_CHANGE:
|
||||
{
|
||||
newcoin::TMStatusChange msg;
|
||||
if(msg.ParseFromArray(&mReadbuf[HEADER_SIZE], mReadbuf.size() - HEADER_SIZE))
|
||||
if (msg.ParseFromArray(&mReadbuf[HEADER_SIZE], mReadbuf.size() - HEADER_SIZE))
|
||||
recvStatus(msg);
|
||||
else std::cerr << "parse error: " << type << std::endl;
|
||||
}
|
||||
@@ -436,7 +484,7 @@ void Peer::processReadBuffer()
|
||||
case newcoin::mtPROPOSE_LEDGER:
|
||||
{
|
||||
newcoin::TMProposeSet msg;
|
||||
if(msg.ParseFromArray(&mReadbuf[HEADER_SIZE], mReadbuf.size() - HEADER_SIZE))
|
||||
if (msg.ParseFromArray(&mReadbuf[HEADER_SIZE], mReadbuf.size() - HEADER_SIZE))
|
||||
recvPropose(msg);
|
||||
else std::cerr << "parse error: " << type << std::endl;
|
||||
}
|
||||
@@ -445,7 +493,7 @@ void Peer::processReadBuffer()
|
||||
case newcoin::mtGET_LEDGER:
|
||||
{
|
||||
newcoin::TMGetLedger msg;
|
||||
if(msg.ParseFromArray(&mReadbuf[HEADER_SIZE], mReadbuf.size() - HEADER_SIZE))
|
||||
if (msg.ParseFromArray(&mReadbuf[HEADER_SIZE], mReadbuf.size() - HEADER_SIZE))
|
||||
recvGetLedger(msg);
|
||||
else std::cerr << "parse error: " << type << std::endl;
|
||||
}
|
||||
@@ -454,7 +502,7 @@ void Peer::processReadBuffer()
|
||||
case newcoin::mtLEDGER_DATA:
|
||||
{
|
||||
newcoin::TMLedgerData msg;
|
||||
if(msg.ParseFromArray(&mReadbuf[HEADER_SIZE], mReadbuf.size() - HEADER_SIZE))
|
||||
if (msg.ParseFromArray(&mReadbuf[HEADER_SIZE], mReadbuf.size() - HEADER_SIZE))
|
||||
recvLedger(msg);
|
||||
else std::cerr << "parse error: " << type << std::endl;
|
||||
}
|
||||
@@ -463,7 +511,7 @@ void Peer::processReadBuffer()
|
||||
case newcoin::mtHAVE_SET:
|
||||
{
|
||||
newcoin::TMHaveTransactionSet msg;
|
||||
if(msg.ParseFromArray(&mReadbuf[HEADER_SIZE], mReadbuf.size() - HEADER_SIZE))
|
||||
if (msg.ParseFromArray(&mReadbuf[HEADER_SIZE], mReadbuf.size() - HEADER_SIZE))
|
||||
recvHaveTxSet(msg);
|
||||
else std::cerr << "parse error: " << type << std::endl;
|
||||
}
|
||||
@@ -472,7 +520,7 @@ void Peer::processReadBuffer()
|
||||
case newcoin::mtVALIDATION:
|
||||
{
|
||||
newcoin::TMValidation msg;
|
||||
if(msg.ParseFromArray(&mReadbuf[HEADER_SIZE], mReadbuf.size() - HEADER_SIZE))
|
||||
if (msg.ParseFromArray(&mReadbuf[HEADER_SIZE], mReadbuf.size() - HEADER_SIZE))
|
||||
recvValidation(msg);
|
||||
else std::cerr << "parse error: " << type << std::endl;
|
||||
}
|
||||
@@ -481,7 +529,7 @@ void Peer::processReadBuffer()
|
||||
case newcoin::mtGET_VALIDATION:
|
||||
{
|
||||
newcoin::TM msg;
|
||||
if(msg.ParseFromArray(&mReadbuf[HEADER_SIZE], mReadbuf.size() - HEADER_SIZE))
|
||||
if (msg.ParseFromArray(&mReadbuf[HEADER_SIZE], mReadbuf.size() - HEADER_SIZE))
|
||||
recv(msg);
|
||||
else std::cerr << "parse error: " << type << std::endl;
|
||||
}
|
||||
@@ -491,7 +539,7 @@ void Peer::processReadBuffer()
|
||||
case newcoin::mtGET_OBJECT:
|
||||
{
|
||||
newcoin::TMGetObjectByHash msg;
|
||||
if(msg.ParseFromArray(&mReadbuf[HEADER_SIZE], mReadbuf.size() - HEADER_SIZE))
|
||||
if (msg.ParseFromArray(&mReadbuf[HEADER_SIZE], mReadbuf.size() - HEADER_SIZE))
|
||||
recvGetObjectByHash(msg);
|
||||
else std::cerr << "parse error: " << type << std::endl;
|
||||
}
|
||||
@@ -500,7 +548,7 @@ void Peer::processReadBuffer()
|
||||
case newcoin::mtOBJECT:
|
||||
{
|
||||
newcoin::TMObjectByHash msg;
|
||||
if(msg.ParseFromArray(&mReadbuf[HEADER_SIZE], mReadbuf.size() - HEADER_SIZE))
|
||||
if (msg.ParseFromArray(&mReadbuf[HEADER_SIZE], mReadbuf.size() - HEADER_SIZE))
|
||||
recvObjectByHash(msg);
|
||||
else std::cerr << "parse error: " << type << std::endl;
|
||||
}
|
||||
@@ -508,6 +556,7 @@ void Peer::processReadBuffer()
|
||||
|
||||
default:
|
||||
std::cerr << "Unknown Msg: " << type << std::endl;
|
||||
std::cerr << strHex(&mReadbuf[0], mReadbuf.size());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -515,63 +564,68 @@ void Peer::processReadBuffer()
|
||||
void Peer::recvHello(newcoin::TMHello& packet)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
std::cerr << "Recv(Hello) v=" << packet.version()
|
||||
<< ", index=" << packet.ledgerindex()
|
||||
<< std::endl;
|
||||
Log(lsINFO) << "Recv(Hello) v=" << packet.version() << ", index=" << packet.ledgerindex();
|
||||
#endif
|
||||
bool bDetach = true;
|
||||
|
||||
// Cancel verification timeout.
|
||||
(void) mVerifyTimer.cancel();
|
||||
|
||||
if (!mNodePublic.setNodePublic(packet.nodepublic()))
|
||||
{
|
||||
std::cerr << "Recv(Hello): Disconnect: Bad node public key." << std::endl;
|
||||
Log(lsINFO) << "Recv(Hello): Disconnect: Bad node public key.";
|
||||
}
|
||||
else if (!mNodePublic.verifyNodePublic(mCookieHash, packet.nodeproof()))
|
||||
{ // Unable to verify they have private key for claimed public key.
|
||||
std::cerr << "Recv(Hello): Disconnect: Failed to verify session." << std::endl;
|
||||
}
|
||||
else if (!theApp->getConnectionPool().peerConnected(shared_from_this(), mNodePublic))
|
||||
{ // Already connected, self, or some other reason.
|
||||
std::cerr << "Recv(Hello): Disconnect: Extraneous connection." << std::endl;
|
||||
Log(lsINFO) << "Recv(Hello): Disconnect: Failed to verify session.";
|
||||
}
|
||||
else
|
||||
{ // Successful connection.
|
||||
|
||||
// Cancel verification timeout.
|
||||
(void) mVerifyTimer.cancel();
|
||||
Log(lsINFO) << "Recv(Hello): Connect: " << mNodePublic.humanNodePublic();
|
||||
|
||||
if (mClientConnect)
|
||||
{
|
||||
theApp->getConnectionPool().peerVerified(mIpPort.first, mIpPort.second);
|
||||
// If we connected due to scan, no longer need to scan.
|
||||
theApp->getConnectionPool().peerVerified(shared_from_this());
|
||||
}
|
||||
|
||||
// No longer connecting as client.
|
||||
mClientConnect = false;
|
||||
if (!theApp->getConnectionPool().peerConnected(shared_from_this(), mNodePublic, getIP(), getPort()))
|
||||
{ // Already connected, self, or some other reason.
|
||||
Log(lsINFO) << "Recv(Hello): Disconnect: Extraneous connection.";
|
||||
}
|
||||
else
|
||||
{
|
||||
// At this point we could add the inbound connection to our IP list. However, the inbound IP address might be that of
|
||||
// a NAT. It would be best to only add it if and only if we can immediately verify it.
|
||||
nothing();
|
||||
if (mClientConnect)
|
||||
{
|
||||
// No longer connecting as client.
|
||||
mClientConnect = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Take a guess at remotes address.
|
||||
std::string strIP = getSocket().remote_endpoint().address().to_string();
|
||||
int iPort = packet.ipv4port();
|
||||
|
||||
theApp->getConnectionPool().savePeer(strIP, iPort, UniqueNodeList::vsInbound);
|
||||
}
|
||||
|
||||
// Consider us connected. No longer accepting mtHELLO.
|
||||
mHelloed = true;
|
||||
|
||||
// XXX Set timer: connection is in grace period to be useful.
|
||||
// XXX Set timer: connection idle (idle may vary depending on connection type.)
|
||||
|
||||
if ((packet.has_closedledger()) && (packet.closedledger().size() == (256 / 8)))
|
||||
{
|
||||
memcpy(mClosedLedgerHash.begin(), packet.closedledger().data(), 256 / 8);
|
||||
if ((packet.has_previousledger()) && (packet.previousledger().size() == (256 / 8)))
|
||||
memcpy(mPreviousLedgerHash.begin(), packet.previousledger().data(), 256 / 8);
|
||||
else mPreviousLedgerHash.zero();
|
||||
mClosedLedgerTime = boost::posix_time::second_clock::universal_time();
|
||||
}
|
||||
|
||||
bDetach = false;
|
||||
}
|
||||
|
||||
// Consider us connected. No longer accepting mtHELLO.
|
||||
mConnected = true;
|
||||
|
||||
// XXX Set timer: connection is in grace period to be useful.
|
||||
// XXX Set timer: connection idle (idle may vary depending on connection type.)
|
||||
|
||||
if ((packet.has_closedledger()) && (packet.closedledger().size() == (256 / 8)))
|
||||
{
|
||||
memcpy(mClosedLedgerHash.begin(), packet.closedledger().data(), 256 / 8);
|
||||
if ((packet.has_previousledger()) && (packet.previousledger().size() == (256 / 8)))
|
||||
memcpy(mPreviousLedgerHash.begin(), packet.previousledger().data(), 256 / 8);
|
||||
else mPreviousLedgerHash.zero();
|
||||
mClosedLedgerTime = boost::posix_time::second_clock::universal_time();
|
||||
}
|
||||
|
||||
|
||||
theApp->getConnectionPool().savePeer(getIP(),packet.ipv4port(),'I');
|
||||
|
||||
bDetach = false;
|
||||
}
|
||||
|
||||
if (bDetach)
|
||||
@@ -579,8 +633,10 @@ void Peer::recvHello(newcoin::TMHello& packet)
|
||||
mNodePublic.clear();
|
||||
detach("recvh");
|
||||
}
|
||||
|
||||
sendGetPeers();
|
||||
else
|
||||
{
|
||||
sendGetPeers();
|
||||
}
|
||||
}
|
||||
|
||||
void Peer::recvTransaction(newcoin::TMTransaction& packet)
|
||||
@@ -632,11 +688,10 @@ void Peer::recvTransaction(newcoin::TMTransaction& packet)
|
||||
|
||||
void Peer::recvPropose(newcoin::TMProposeSet& packet)
|
||||
{
|
||||
Log(lsINFO) << "Received proposal from peer";
|
||||
if ((packet.currenttxhash().size() != 32) || (packet.nodepubkey().size() < 28) ||
|
||||
(packet.signature().size() < 56))
|
||||
{
|
||||
Log(lsWARNING) << "Proposal is malformed";
|
||||
Log(lsWARNING) << "Received proposal is malformed";
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -645,7 +700,7 @@ void Peer::recvPropose(newcoin::TMProposeSet& packet)
|
||||
memcpy(currentTxHash.begin(), packet.currenttxhash().data(), 32);
|
||||
|
||||
if(theApp->getOPs().recvPropose(proposeSeq, currentTxHash, packet.nodepubkey(), packet.signature()))
|
||||
{ // FIXME: Not all nodes will want proposals
|
||||
{ // FIXME: Not all nodes will want proposals
|
||||
PackedMessage::pointer message = boost::make_shared<PackedMessage>(packet, newcoin::mtPROPOSE_LEDGER);
|
||||
theApp->getConnectionPool().relayMessage(this, message);
|
||||
}
|
||||
@@ -713,43 +768,52 @@ void Peer::recvGetContacts(newcoin::TMGetContacts& packet)
|
||||
void Peer::recvGetPeers(newcoin::TMGetPeers& packet)
|
||||
{
|
||||
std::vector<std::string> addrs;
|
||||
theApp->getConnectionPool().getTopNAddrs(30,addrs);
|
||||
if(addrs.size())
|
||||
|
||||
theApp->getConnectionPool().getTopNAddrs(30, addrs);
|
||||
|
||||
if (!addrs.empty())
|
||||
{
|
||||
newcoin::TMPeers peers;
|
||||
|
||||
for(int n=0; n<addrs.size(); n++)
|
||||
for (int n=0; n<addrs.size(); n++)
|
||||
{
|
||||
std::string strIP;
|
||||
int port;
|
||||
splitIpPort(addrs[n],strIP,port);
|
||||
int iPort;
|
||||
|
||||
splitIpPort(addrs[n], strIP, iPort);
|
||||
|
||||
// XXX This should also ipv6
|
||||
newcoin::TMIPv4EndPoint* addr=peers.add_nodes();
|
||||
addr->set_ipv4(inet_addr(strIP.c_str()));
|
||||
addr->set_ipv4port(port);
|
||||
addr->set_ipv4port(iPort);
|
||||
|
||||
std::cout << "Teaching about: " << strIP << std::endl;
|
||||
Log(lsINFO) << "Peer: Teaching: " << ADDRESS(this) << ": " << n << ": " << strIP << " " << iPort;
|
||||
}
|
||||
|
||||
|
||||
PackedMessage::pointer message = boost::make_shared<PackedMessage>(peers, newcoin::mtPEERS);
|
||||
sendPacket(message);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: filter out all the LAN peers
|
||||
void Peer::recvPeers(newcoin::TMPeers& packet)
|
||||
{
|
||||
for(int i = 0; i < packet.nodes().size(); ++i)
|
||||
for (int i = 0; i < packet.nodes().size(); ++i)
|
||||
{
|
||||
in_addr addr;
|
||||
addr.s_addr=packet.nodes(i).ipv4();
|
||||
std::string strIP( inet_ntoa(addr));
|
||||
int port=packet.nodes(i).ipv4port();
|
||||
|
||||
std::cout << "Learning about: " << strIP << std::endl;
|
||||
addr.s_addr = packet.nodes(i).ipv4();
|
||||
|
||||
theApp->getConnectionPool().savePeer(strIP,port,'T');
|
||||
std::string strIP(inet_ntoa(addr));
|
||||
int iPort = packet.nodes(i).ipv4port();
|
||||
|
||||
if (strIP != "0.0.0.0" && strIP != "127.0.0.1")
|
||||
{
|
||||
Log(lsINFO) << "Peer: Learning: " << ADDRESS(this) << ": " << i << ": " << strIP << " " << iPort;
|
||||
|
||||
theApp->getConnectionPool().savePeer(strIP, iPort, UniqueNodeList::vsTold);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void Peer::recvIndexedObject(newcoin::TMIndexedObject& packet)
|
||||
@@ -791,21 +855,30 @@ void Peer::recvStatus(newcoin::TMStatusChange& packet)
|
||||
packet.set_networktime(theApp->getOPs().getNetworkTimeNC());
|
||||
mLastStatus = packet;
|
||||
|
||||
if (packet.newevent() == newcoin::neLOST_SYNC)
|
||||
{
|
||||
Log(lsTRACE) << "peer has lost sync";
|
||||
mPreviousLedgerHash.zero();
|
||||
mClosedLedgerHash.zero();
|
||||
return;
|
||||
}
|
||||
if (packet.has_ledgerhash() && (packet.ledgerhash().size() == (256 / 8)))
|
||||
{ // a peer has changed ledgers
|
||||
if (packet.has_previousledgerhash() && (packet.previousledgerhash().size() == (256 / 8)))
|
||||
memcpy(mPreviousLedgerHash.begin(), packet.previousledgerhash().data(), 256 / 8);
|
||||
else
|
||||
mPreviousLedgerHash = mClosedLedgerHash;
|
||||
memcpy(mClosedLedgerHash.begin(), packet.ledgerhash().data(), 256 / 8);
|
||||
mClosedLedgerTime = ptFromSeconds(packet.networktime());
|
||||
Log(lsTRACE) << "peer LCL is " << mClosedLedgerHash.GetHex();
|
||||
}
|
||||
else if(packet.has_previousledgerhash() && packet.previousledgerhash().size() == (256 / 8))
|
||||
else
|
||||
{
|
||||
memcpy(mClosedLedgerHash.begin(), packet.previousledgerhash().data(), 256 / 8);
|
||||
mClosedLedgerTime = ptFromSeconds(packet.networktime());
|
||||
Log(lsTRACE) << "peer has no ledger hash";
|
||||
mClosedLedgerHash.zero();
|
||||
}
|
||||
|
||||
if (packet.has_previousledgerhash() && packet.previousledgerhash().size() == (256 / 8))
|
||||
{
|
||||
memcpy(mPreviousLedgerHash.begin(), packet.previousledgerhash().data(), 256 / 8);
|
||||
}
|
||||
else mPreviousLedgerHash.zero();
|
||||
}
|
||||
|
||||
void Peer::recvGetLedger(newcoin::TMGetLedger& packet)
|
||||
@@ -1047,12 +1120,14 @@ void Peer::sendGetPeers()
|
||||
{
|
||||
// get other peers this guy knows about
|
||||
newcoin::TMGetPeers getPeers;
|
||||
|
||||
getPeers.set_doweneedthis(1);
|
||||
|
||||
PackedMessage::pointer packet = boost::make_shared<PackedMessage>(getPeers, newcoin::mtGET_PEERS);
|
||||
|
||||
sendPacket(packet);
|
||||
}
|
||||
|
||||
|
||||
void Peer::punishPeer(PeerPunish)
|
||||
{
|
||||
}
|
||||
@@ -1060,9 +1135,16 @@ void Peer::punishPeer(PeerPunish)
|
||||
Json::Value Peer::getJson() {
|
||||
Json::Value ret(Json::objectValue);
|
||||
|
||||
ret["ip"] = mIpPort.first;
|
||||
ret["port"] = mIpPort.second;
|
||||
ret["this"] = ADDRESS(this);
|
||||
ret["public_key"] = mNodePublic.ToString();
|
||||
ret["ip"] = mIpPortConnect.first;
|
||||
ret["port"] = mIpPortConnect.second;
|
||||
|
||||
if (!mIpPort.first.empty())
|
||||
{
|
||||
ret["verified_ip"] = mIpPort.first;
|
||||
ret["verified_port"] = mIpPort.second;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
14
src/Peer.h
14
src/Peer.h
@@ -31,9 +31,11 @@ public:
|
||||
|
||||
private:
|
||||
bool mClientConnect; // In process of connecting as client.
|
||||
bool mConnected; // True, if hello accepted.
|
||||
bool mHelloed; // True, if hello accepted.
|
||||
bool mDetaching; // True, if detaching.
|
||||
NewcoinAddress mNodePublic; // Node public key of peer.
|
||||
ipPort mIpPort;
|
||||
ipPort mIpPortConnect;
|
||||
uint256 mCookieHash;
|
||||
|
||||
// network state information
|
||||
@@ -56,6 +58,8 @@ protected:
|
||||
|
||||
Peer(boost::asio::io_service& io_service, boost::asio::ssl::context& ctx);
|
||||
|
||||
void handleShutdown(const boost::system::error_code& error) { ; }
|
||||
|
||||
void handle_write(const boost::system::error_code& error, size_t bytes_transferred);
|
||||
void handle_read_header(const boost::system::error_code& error);
|
||||
void handle_read_body(const boost::system::error_code& error);
|
||||
@@ -96,8 +100,10 @@ public:
|
||||
|
||||
//bool operator == (const Peer& other);
|
||||
|
||||
std::string& getIP(){ return(mIpPort.first); }
|
||||
int getPort(){ return(mIpPort.second); }
|
||||
std::string& getIP() { return mIpPort.first; }
|
||||
int getPort() { return mIpPort.second; }
|
||||
|
||||
void setIpPort(const std::string& strIP, int iPort);
|
||||
|
||||
static pointer create(boost::asio::io_service& io_service, boost::asio::ssl::context& ctx)
|
||||
{
|
||||
@@ -124,6 +130,7 @@ public:
|
||||
void punishPeer(PeerPunish pp);
|
||||
|
||||
Json::Value getJson();
|
||||
bool isConnected() const { return mHelloed && !mDetaching; }
|
||||
|
||||
//static PackedMessage::pointer createFullLedger(Ledger::pointer ledger);
|
||||
static PackedMessage::pointer createLedgerProposal(Ledger::pointer ledger);
|
||||
@@ -132,6 +139,7 @@ public:
|
||||
|
||||
uint256 getClosedLedgerHash() const { return mClosedLedgerHash; }
|
||||
NewcoinAddress getNodePublic() const { return mNodePublic; }
|
||||
void cycleStatus() { mPreviousLedgerHash = mClosedLedgerHash; mClosedLedgerHash.zero(); }
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "AccountState.h"
|
||||
#include "NicknameState.h"
|
||||
#include "utils.h"
|
||||
#include "Log.h"
|
||||
|
||||
RPCServer::RPCServer(boost::asio::io_service& io_service , NetworkOPs* nopNetwork)
|
||||
: mNetOps(nopNetwork), mSocket(io_service)
|
||||
@@ -162,16 +163,10 @@ std::string RPCServer::handleRequest(const std::string& requestStr)
|
||||
else if (!valParams.isArray())
|
||||
return(HTTPReply(400, ""));
|
||||
|
||||
#ifdef DEBUG
|
||||
Json::StyledStreamWriter w;
|
||||
w.write(std::cerr, valParams);
|
||||
#endif
|
||||
|
||||
w.write(Log(lsTRACE).ref(), valParams);
|
||||
Json::Value result(doCommand(strMethod, valParams));
|
||||
|
||||
#ifdef DEBUG
|
||||
w.write(std::cerr, result);
|
||||
#endif
|
||||
w.write(Log(lsTRACE).ref(), result);
|
||||
|
||||
std::string strReply = JSONRPCReply(result, Json::Value(), id);
|
||||
return( HTTPReply(200, strReply) );
|
||||
@@ -728,8 +723,8 @@ Json::Value RPCServer::doConnect(Json::Value& params)
|
||||
iPort = boost::lexical_cast<int>(strPort);
|
||||
}
|
||||
|
||||
if (!theApp->getConnectionPool().connectTo(strIp, iPort))
|
||||
return "connected";
|
||||
// XXX Validate legal IP and port
|
||||
theApp->getConnectionPool().connectTo(strIp, iPort);
|
||||
|
||||
return "connecting";
|
||||
}
|
||||
@@ -1236,6 +1231,13 @@ Json::Value RPCServer::doSend(Json::Value& params)
|
||||
}
|
||||
}
|
||||
|
||||
Json::Value RPCServer::doServerInfo(Json::Value& params)
|
||||
{
|
||||
Json::Value ret(Json::objectValue);
|
||||
ret["info"]=theApp->getOPs().getServerInfo();
|
||||
return ret;
|
||||
}
|
||||
|
||||
// transit_set <seed> <paying_account> <transit_rate> <starts> <expires>
|
||||
Json::Value RPCServer::doTransitSet(Json::Value& params)
|
||||
{
|
||||
@@ -1966,7 +1968,7 @@ Json::Value RPCServer::doStop(Json::Value& params) {
|
||||
|
||||
Json::Value RPCServer::doCommand(const std::string& command, Json::Value& params)
|
||||
{
|
||||
std::cerr << "RPC:" << command << std::endl;
|
||||
Log(lsTRACE) << "RPC:" << command;
|
||||
|
||||
static struct {
|
||||
const char* pCommand;
|
||||
@@ -1993,6 +1995,7 @@ Json::Value RPCServer::doCommand(const std::string& command, Json::Value& params
|
||||
{ "password_set", &RPCServer::doPasswordSet, 2, 3, optNetwork },
|
||||
{ "peers", &RPCServer::doPeers, 0, 0, },
|
||||
{ "send", &RPCServer::doSend, 3, 7, optCurrent },
|
||||
{ "server_info", &RPCServer::doServerInfo, 0, 0, },
|
||||
{ "stop", &RPCServer::doStop, 0, 0, },
|
||||
{ "transit_set", &RPCServer::doTransitSet, 5, 5, optCurrent },
|
||||
{ "tx", &RPCServer::doTx, 1, 1, },
|
||||
|
||||
@@ -127,6 +127,7 @@ private:
|
||||
Json::Value doPasswordSet(Json::Value& params);
|
||||
Json::Value doPeers(Json::Value& params);
|
||||
Json::Value doSend(Json::Value& params);
|
||||
Json::Value doServerInfo(Json::Value& params);
|
||||
Json::Value doSessionClose(Json::Value& params);
|
||||
Json::Value doSessionOpen(Json::Value& params);
|
||||
Json::Value doStop(Json::Value& params);
|
||||
|
||||
@@ -485,6 +485,17 @@ STAmount STObject::getValueFieldAmount(SOE_Field field) const
|
||||
return *cf;
|
||||
}
|
||||
|
||||
STPathSet STObject::getValueFieldPathSet(SOE_Field field) const
|
||||
{
|
||||
const SerializedType* rf = peekAtPField(field);
|
||||
if (!rf) throw std::runtime_error("Field not found");
|
||||
SerializedTypeID id = rf->getSType();
|
||||
if (id == STI_NOTPRESENT) return STPathSet(); // optional field not present
|
||||
const STPathSet *cf = dynamic_cast<const STPathSet *>(rf);
|
||||
if (!cf) throw std::runtime_error("Wrong field type");
|
||||
return *cf;
|
||||
}
|
||||
|
||||
STVector256 STObject::getValueFieldV256(SOE_Field field) const
|
||||
{
|
||||
const SerializedType* rf = peekAtPField(field);
|
||||
|
||||
@@ -38,6 +38,7 @@ enum SOE_Field
|
||||
sfBorrowRate,
|
||||
sfBorrowStart,
|
||||
sfBorrower,
|
||||
sfCloseTime,
|
||||
sfCurrency,
|
||||
sfCurrencyIn,
|
||||
sfCurrencyOut,
|
||||
@@ -166,6 +167,7 @@ public:
|
||||
std::vector<unsigned char> getValueFieldVL(SOE_Field field) const;
|
||||
std::vector<TaggedListItem> getValueFieldTL(SOE_Field field) const;
|
||||
STAmount getValueFieldAmount(SOE_Field field) const;
|
||||
STPathSet getValueFieldPathSet(SOE_Field field) const;
|
||||
STVector256 getValueFieldV256(SOE_Field field) const;
|
||||
|
||||
void setValueFieldU8(SOE_Field field, unsigned char);
|
||||
|
||||
@@ -89,6 +89,7 @@ public:
|
||||
std::vector<unsigned char> getITFieldVL(SOE_Field field) const { return mInnerTxn.getValueFieldVL(field); }
|
||||
std::vector<TaggedListItem> getITFieldTL(SOE_Field field) const { return mInnerTxn.getValueFieldTL(field); }
|
||||
STAmount getITFieldAmount(SOE_Field field) const { return mInnerTxn.getValueFieldAmount(field); }
|
||||
STPathSet getITFieldPathSet(SOE_Field field) const { return mInnerTxn.getValueFieldPathSet(field); }
|
||||
|
||||
void setITFieldU8(SOE_Field field, unsigned char v) { return mInnerTxn.setValueFieldU8(field, v); }
|
||||
void setITFieldU16(SOE_Field field, uint16 v) { return mInnerTxn.setValueFieldU16(field, v); }
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
SOElement SerializedValidation::sValidationFormat[] = {
|
||||
{ sfFlags, "Flags", STI_UINT32, SOE_FLAGS, 0 },
|
||||
{ sfLedgerHash, "LedgerHash", STI_HASH256, SOE_REQUIRED, 0 },
|
||||
{ sfCloseTime, "CloseTime", STI_UINT64, SOE_REQUIRED, 0 },
|
||||
{ sfSigningKey, "SigningKey", STI_VL, SOE_REQUIRED, 0 },
|
||||
{ sfExtensions, "Extensions", STI_TL, SOE_IFFLAG, 0x01000000 },
|
||||
{ sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 },
|
||||
@@ -18,11 +19,14 @@ SerializedValidation::SerializedValidation(SerializerIterator& sit, bool checkSi
|
||||
if (!isValid()) throw std::runtime_error("Invalid validation");
|
||||
}
|
||||
|
||||
SerializedValidation::SerializedValidation(const uint256& ledgerHash, const NewcoinAddress& naSeed, bool isFull)
|
||||
SerializedValidation::SerializedValidation(const uint256& ledgerHash, uint64 closeTime,
|
||||
const NewcoinAddress& naSeed, bool isFull)
|
||||
: STObject(sValidationFormat), mSignature("Signature"), mTrusted(false)
|
||||
{
|
||||
setValueFieldH256(sfLedgerHash, ledgerHash);
|
||||
setValueFieldVL(sfSigningKey, NewcoinAddress::createNodePublic(naSeed).getNodePublic());
|
||||
setValueFieldU64(sfCloseTime, closeTime);
|
||||
if (naSeed.isValid())
|
||||
setValueFieldVL(sfSigningKey, NewcoinAddress::createNodePublic(naSeed).getNodePublic());
|
||||
if (!isFull) setFlag(sFullFlag);
|
||||
|
||||
NewcoinAddress::createNodePrivate(naSeed).signNodePrivate(getSigningHash(), mSignature.peekValue());
|
||||
@@ -46,6 +50,11 @@ uint256 SerializedValidation::getLedgerHash() const
|
||||
return getValueFieldH256(sfLedgerHash);
|
||||
}
|
||||
|
||||
uint64 SerializedValidation::getCloseTime() const
|
||||
{
|
||||
return getValueFieldU64(sfCloseTime);
|
||||
}
|
||||
|
||||
bool SerializedValidation::isValid() const
|
||||
{
|
||||
try
|
||||
|
||||
@@ -23,9 +23,10 @@ public:
|
||||
SerializedValidation(SerializerIterator& sit, bool checkSignature = true);
|
||||
SerializedValidation(const Serializer& s, bool checkSignature = true);
|
||||
|
||||
SerializedValidation(const uint256& ledgerHash, const NewcoinAddress& naSeed, bool isFull);
|
||||
SerializedValidation(const uint256& ledgerHash, uint64 closeTime, const NewcoinAddress& naSeed, bool isFull);
|
||||
|
||||
uint256 getLedgerHash() const;
|
||||
uint64 getCloseTime() const;
|
||||
NewcoinAddress getSignerPublic() const;
|
||||
bool isValid() const;
|
||||
bool isFull() const;
|
||||
@@ -33,7 +34,7 @@ public:
|
||||
CKey::pointer getSigningKey() const;
|
||||
uint256 getSigningHash() const;
|
||||
|
||||
void setTrusted() { mTrusted = true; }
|
||||
void setTrusted() { mTrusted = true; }
|
||||
void addSigned(Serializer&) const;
|
||||
void addSignature(Serializer&) const;
|
||||
std::vector<unsigned char> getSigned() const;
|
||||
|
||||
37
src/Suppression.cpp
Normal file
37
src/Suppression.cpp
Normal file
@@ -0,0 +1,37 @@
|
||||
|
||||
#include "Suppression.h"
|
||||
|
||||
bool SuppressionTable::addSuppression(const uint160& suppression)
|
||||
{
|
||||
boost::mutex::scoped_lock sl(mSuppressionMutex);
|
||||
|
||||
if (mSuppressionMap.find(suppression) != mSuppressionMap.end())
|
||||
return false;
|
||||
|
||||
time_t now = time(NULL);
|
||||
|
||||
boost::unordered_map< time_t, std::list<uint160> >::iterator it = mSuppressionTimes.begin();
|
||||
while (it != mSuppressionTimes.end())
|
||||
{
|
||||
if ((it->first + mHoldTime) < now)
|
||||
{
|
||||
for (std::list<uint160>::iterator lit = it->second.begin(), end = it->second.end();
|
||||
lit != end; ++lit)
|
||||
mSuppressionMap.erase(*lit);
|
||||
it = mSuppressionTimes.erase(it);
|
||||
}
|
||||
else ++it;
|
||||
}
|
||||
|
||||
mSuppressionMap[suppression] = now;
|
||||
mSuppressionTimes[now].push_back(suppression);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SuppressionTable::addSuppression(const uint256& suppression)
|
||||
{
|
||||
uint160 u;
|
||||
memcpy(u.begin(), suppression.begin() + (suppression.size() - u.size()), u.size());
|
||||
return addSuppression(u);
|
||||
}
|
||||
34
src/Suppression.h
Normal file
34
src/Suppression.h
Normal file
@@ -0,0 +1,34 @@
|
||||
#ifndef __SUPPRESSION__
|
||||
#define __SUPPRESSION__
|
||||
|
||||
#include <list>
|
||||
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
|
||||
#include "uint256.h"
|
||||
|
||||
extern std::size_t hash_value(const uint160& u);
|
||||
|
||||
class SuppressionTable
|
||||
{
|
||||
protected:
|
||||
|
||||
boost::mutex mSuppressionMutex;
|
||||
|
||||
// Stores all suppressed hashes and their expiration time
|
||||
boost::unordered_map<uint160, time_t> mSuppressionMap;
|
||||
|
||||
// Stores all expiration times and the hashes indexed for them
|
||||
boost::unordered_map< time_t, std::list<uint160> > mSuppressionTimes;
|
||||
|
||||
int mHoldTime;
|
||||
|
||||
public:
|
||||
SuppressionTable(int holdTime = 120) : mHoldTime(holdTime) { ; }
|
||||
|
||||
bool addSuppression(const uint256& suppression);
|
||||
bool addSuppression(const uint160& suppression);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,6 +1,11 @@
|
||||
//
|
||||
// XXX Should make sure all fields and are recognized on a transactions.
|
||||
// XXX Make sure fee is claimed for failed transactions.
|
||||
//
|
||||
|
||||
#include "TransactionEngine.h"
|
||||
|
||||
#include <boost/foreach.hpp>
|
||||
#include <boost/format.hpp>
|
||||
|
||||
#include "../json/writer.h"
|
||||
@@ -40,12 +45,12 @@ TransactionEngineResult TransactionEngine::dirAdd(
|
||||
|
||||
|
||||
sleRoot->setIndex(uRootIndex);
|
||||
std::cerr << "dirAdd: Creating dir index: " << sleRoot->getIndex().ToString() << std::endl;
|
||||
Log(lsTRACE) << "dirAdd: Creating dir index: " << sleRoot->getIndex().ToString();
|
||||
|
||||
sleRoot->setIFieldU64(sfFirstNode, uNodeDir);
|
||||
sleRoot->setIFieldU64(sfLastNode, uNodeDir);
|
||||
|
||||
std::cerr << "dirAdd: first & last: " << strHex(uNodeDir) << std::endl;
|
||||
Log(lsTRACE) << "dirAdd: first & last: " << strHex(uNodeDir);
|
||||
|
||||
accounts.push_back(std::make_pair(taaCREATE, sleRoot));
|
||||
}
|
||||
@@ -64,9 +69,9 @@ TransactionEngineResult TransactionEngine::dirAdd(
|
||||
{
|
||||
// Last node is not full, append.
|
||||
|
||||
std::cerr << "dirAdd: appending: PREV: " << svIndexes.peekValue()[0].ToString() << std::endl;
|
||||
std::cerr << "dirAdd: appending: Node: " << strHex(uNodeDir) << std::endl;
|
||||
std::cerr << "dirAdd: appending: Entry: " << uLedgerIndex.ToString() << std::endl;
|
||||
Log(lsTRACE) << "dirAdd: appending: PREV: " << svIndexes.peekValue()[0].ToString();
|
||||
Log(lsTRACE) << "dirAdd: appending: Node: " << strHex(uNodeDir);
|
||||
Log(lsTRACE) << "dirAdd: appending: Entry: " << uLedgerIndex.ToString();
|
||||
|
||||
svIndexes.peekValue().push_back(uLedgerIndex);
|
||||
sleNode->setIFieldV256(sfIndexes, svIndexes);
|
||||
@@ -83,7 +88,7 @@ TransactionEngineResult TransactionEngine::dirAdd(
|
||||
// Record new last node.
|
||||
sleNode = SLE::pointer();
|
||||
|
||||
std::cerr << "dirAdd: last: " << strHex(uNodeDir) << std::endl;
|
||||
Log(lsTRACE) << "dirAdd: last: " << strHex(uNodeDir);
|
||||
|
||||
sleRoot->setIFieldU64(sfLastNode, uNodeDir);
|
||||
|
||||
@@ -97,7 +102,7 @@ TransactionEngineResult TransactionEngine::dirAdd(
|
||||
sleNode = boost::make_shared<SerializedLedgerEntry>(ltDIR_NODE);
|
||||
sleNode->setIndex(uNodeIndex);
|
||||
|
||||
std::cerr << "dirAdd: Creating dir node: " << sleNode->getIndex().ToString() << std::endl;
|
||||
Log(lsTRACE) << "dirAdd: Creating dir node: " << sleNode->getIndex().ToString();
|
||||
|
||||
STVector256 svIndexes;
|
||||
|
||||
@@ -123,7 +128,7 @@ TransactionEngineResult TransactionEngine::dirDelete(
|
||||
|
||||
if (!sleNode)
|
||||
{
|
||||
std::cerr << "dirDelete: no such node" << std::endl;
|
||||
Log(lsWARNING) << "dirDelete: no such node";
|
||||
return terNODE_NOT_FOUND;
|
||||
}
|
||||
else
|
||||
@@ -135,7 +140,7 @@ TransactionEngineResult TransactionEngine::dirDelete(
|
||||
it = std::find(vuiIndexes.begin(), vuiIndexes.end(), uLedgerIndex);
|
||||
if (vuiIndexes.end() == it)
|
||||
{
|
||||
std::cerr << "dirDelete: node not mentioned" << std::endl;
|
||||
Log(lsWARNING) << "dirDelete: node not mentioned";
|
||||
return terNODE_NOT_MENTIONED;
|
||||
}
|
||||
else
|
||||
@@ -146,7 +151,7 @@ TransactionEngineResult TransactionEngine::dirDelete(
|
||||
|
||||
if (!sleRoot)
|
||||
{
|
||||
std::cerr << "dirDelete: root node is missing" << std::endl;
|
||||
Log(lsWARNING) << "dirDelete: root node is missing";
|
||||
return terNODE_NO_ROOT;
|
||||
}
|
||||
|
||||
@@ -242,7 +247,7 @@ TransactionEngineResult TransactionEngine::setAuthorized(const SerializedTransac
|
||||
|
||||
if (!naAccountPublic.accountPublicVerify(Serializer::getSHA512Half(vucCipher), vucSignature))
|
||||
{
|
||||
std::cerr << "createGenerator: bad signature unauthorized generator claim" << std::endl;
|
||||
Log(lsWARNING) << "createGenerator: bad signature unauthorized generator claim";
|
||||
|
||||
return tenBAD_GEN_AUTH;
|
||||
}
|
||||
@@ -254,7 +259,7 @@ TransactionEngineResult TransactionEngine::setAuthorized(const SerializedTransac
|
||||
SLE::pointer sleGen = mLedger->getGenerator(qry, hGeneratorID);
|
||||
if (!sleGen)
|
||||
{
|
||||
std::cerr << "createGenerator: creating generator" << std::endl;
|
||||
Log(lsTRACE) << "createGenerator: creating generator";
|
||||
// Create the generator.
|
||||
sleGen = boost::make_shared<SerializedLedgerEntry>(ltGENERATOR_MAP);
|
||||
|
||||
@@ -268,7 +273,7 @@ TransactionEngineResult TransactionEngine::setAuthorized(const SerializedTransac
|
||||
{
|
||||
// Doing a claim. Must set generator.
|
||||
// Generator is already in use. Regular passphrases limited to one wallet.
|
||||
std::cerr << "createGenerator: generator already in use" << std::endl;
|
||||
Log(lsWARNING) << "createGenerator: generator already in use";
|
||||
|
||||
return tenGEN_IN_USE;
|
||||
}
|
||||
@@ -288,7 +293,7 @@ TransactionEngineResult TransactionEngine::setAuthorized(const SerializedTransac
|
||||
TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTransaction& txn,
|
||||
TransactionEngineParams params, uint32 targetLedger)
|
||||
{
|
||||
std::cerr << "applyTransaction>" << std::endl;
|
||||
Log(lsTRACE) << "applyTransaction>";
|
||||
|
||||
mLedger = mDefaultLedger;
|
||||
assert(mLedger);
|
||||
@@ -308,7 +313,7 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran
|
||||
SerializedTransaction s2(sit);
|
||||
if (!s2.isEquivalent(txn))
|
||||
{
|
||||
std::cerr << "Transaction serdes mismatch" << std::endl;
|
||||
Log(lsFATAL) << "Transaction serdes mismatch";
|
||||
Json::StyledStreamWriter ssw;
|
||||
ssw.write(Log(lsINFO).ref(), txn.getJson(0));
|
||||
ssw.write(Log(lsFATAL).ref(), s2.getJson(0));
|
||||
@@ -322,7 +327,7 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran
|
||||
uint256 txID = txn.getTransactionID();
|
||||
if (!txID)
|
||||
{
|
||||
std::cerr << "applyTransaction: invalid transaction id" << std::endl;
|
||||
Log(lsWARNING) << "applyTransaction: invalid transaction id";
|
||||
|
||||
result = tenINVALID;
|
||||
}
|
||||
@@ -344,7 +349,7 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran
|
||||
// Consistency: really signed.
|
||||
if (terSUCCESS == result && !txn.checkSign(naSigningPubKey))
|
||||
{
|
||||
std::cerr << "applyTransaction: Invalid transaction: bad signature" << std::endl;
|
||||
Log(lsWARNING) << "applyTransaction: Invalid transaction: bad signature";
|
||||
|
||||
result = tenINVALID;
|
||||
}
|
||||
@@ -389,12 +394,12 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran
|
||||
break;
|
||||
|
||||
case ttINVALID:
|
||||
std::cerr << "applyTransaction: Invalid transaction: ttINVALID transaction type" << std::endl;
|
||||
Log(lsWARNING) << "applyTransaction: Invalid transaction: ttINVALID transaction type";
|
||||
result = tenINVALID;
|
||||
break;
|
||||
|
||||
default:
|
||||
std::cerr << "applyTransaction: Invalid transaction: unknown transaction type" << std::endl;
|
||||
Log(lsWARNING) << "applyTransaction: Invalid transaction: unknown transaction type";
|
||||
result = tenUNKNOWN;
|
||||
break;
|
||||
}
|
||||
@@ -408,7 +413,7 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran
|
||||
{
|
||||
if (saPaid < saCost)
|
||||
{
|
||||
std::cerr << "applyTransaction: insufficient fee" << std::endl;
|
||||
Log(lsINFO) << "applyTransaction: insufficient fee";
|
||||
|
||||
result = tenINSUF_FEE_P;
|
||||
}
|
||||
@@ -418,7 +423,7 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran
|
||||
if (!saPaid.isZero())
|
||||
{
|
||||
// Transaction is malformed.
|
||||
std::cerr << "applyTransaction: fee not allowed" << std::endl;
|
||||
Log(lsWARNING) << "applyTransaction: fee not allowed";
|
||||
|
||||
result = tenINSUF_FEE_P;
|
||||
}
|
||||
@@ -429,7 +434,7 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran
|
||||
uint160 srcAccountID = txn.getSourceAccount().getAccountID();
|
||||
if (terSUCCESS == result && !srcAccountID)
|
||||
{
|
||||
std::cerr << "applyTransaction: bad source id" << std::endl;
|
||||
Log(lsWARNING) << "applyTransaction: bad source id";
|
||||
|
||||
result = tenINVALID;
|
||||
}
|
||||
@@ -455,7 +460,8 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran
|
||||
|
||||
if (!sleSrc)
|
||||
{
|
||||
std::cerr << str(boost::format("applyTransaction: Delay transaction: source account does not exisit: %s") % txn.getSourceAccount().humanAccountID()) << std::endl;
|
||||
Log(lsTRACE) << str(boost::format("applyTransaction: Delay transaction: source account does not exist: %s") %
|
||||
txn.getSourceAccount().humanAccountID());
|
||||
|
||||
result = terNO_ACCOUNT;
|
||||
}
|
||||
@@ -473,7 +479,7 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran
|
||||
case ttCLAIM:
|
||||
if (bHaveAuthKey)
|
||||
{
|
||||
std::cerr << "applyTransaction: Account already claimed." << std::endl;
|
||||
Log(lsWARNING) << "applyTransaction: Account already claimed.";
|
||||
|
||||
result = tenCLAIMED;
|
||||
}
|
||||
@@ -496,8 +502,8 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran
|
||||
if (naSigningPubKey.getAccountID() != srcAccountID)
|
||||
{
|
||||
// Signing Pub Key must be for Source Account ID.
|
||||
std::cerr << "sourceAccountID: " << naSigningPubKey.humanAccountID() << std::endl;
|
||||
std::cerr << "txn accountID: " << txn.getSourceAccount().humanAccountID() << std::endl;
|
||||
Log(lsWARNING) << "sourceAccountID: " << naSigningPubKey.humanAccountID();
|
||||
Log(lsWARNING) << "txn accountID: " << txn.getSourceAccount().humanAccountID();
|
||||
|
||||
result = tenBAD_CLAIM_ID;
|
||||
}
|
||||
@@ -509,8 +515,8 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran
|
||||
if (naSigningPubKey.getAccountID() != srcAccountID)
|
||||
{
|
||||
// Signing Pub Key must be for Source Account ID.
|
||||
std::cerr << "sourceAccountID: " << naSigningPubKey.humanAccountID() << std::endl;
|
||||
std::cerr << "txn accountID: " << txn.getSourceAccount().humanAccountID() << std::endl;
|
||||
Log(lsWARNING) << "sourceAccountID: " << naSigningPubKey.humanAccountID();
|
||||
Log(lsWARNING) << "txn accountID: " << txn.getSourceAccount().humanAccountID();
|
||||
|
||||
result = tenBAD_SET_ID;
|
||||
}
|
||||
@@ -573,12 +579,12 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran
|
||||
else if (!saCost.isZero())
|
||||
{
|
||||
uint32 a_seq = sleSrc->getIFieldU32(sfSequence);
|
||||
Log(lsINFO) << "Aseq=" << a_seq << ", Tseq=" << t_seq;
|
||||
Log(lsTRACE) << "Aseq=" << a_seq << ", Tseq=" << t_seq;
|
||||
if (t_seq != a_seq)
|
||||
{
|
||||
if (a_seq < t_seq)
|
||||
{
|
||||
std::cerr << "applyTransaction: future sequence number" << std::endl;
|
||||
Log(lsTRACE) << "applyTransaction: future sequence number";
|
||||
|
||||
result = terPRE_SEQ;
|
||||
}
|
||||
@@ -1007,10 +1013,15 @@ TransactionEngineResult TransactionEngine::doPasswordSet(const SerializedTransac
|
||||
|
||||
TransactionEngineResult TransactionEngine::doPayment(const SerializedTransaction& txn,
|
||||
std::vector<AffectedAccount>& accounts,
|
||||
const uint160& srcAccountID)
|
||||
const uint160& uSrcAccountID)
|
||||
{
|
||||
uint32 txFlags = txn.getFlags();
|
||||
uint160 uDstAccountID = txn.getITFieldAccount(sfDestination);
|
||||
uint32 txFlags = txn.getFlags();
|
||||
uint160 uDstAccountID = txn.getITFieldAccount(sfDestination);
|
||||
// XXX Could also be ripple if direct credit lines.
|
||||
bool bRipple = txn.getITFieldPresent(sfPaths);
|
||||
bool bCreate = !!(txFlags & tfCreateAccount);
|
||||
STAmount saAmount = txn.getITFieldAmount(sfAmount);
|
||||
STAmount saSrcBalance = accounts[0].second->getIValueFieldAmount(sfBalance);
|
||||
|
||||
if (!uDstAccountID)
|
||||
{
|
||||
@@ -1018,38 +1029,30 @@ TransactionEngineResult TransactionEngine::doPayment(const SerializedTransaction
|
||||
return tenINVALID;
|
||||
}
|
||||
// XXX Only bad if no currency conversion in between through other people's offer.
|
||||
else if (srcAccountID == uDstAccountID)
|
||||
else if (uSrcAccountID == uDstAccountID)
|
||||
{
|
||||
std::cerr << "doPayment: Invalid transaction: Source account is the same as destination." << std::endl;
|
||||
return tenINVALID;
|
||||
}
|
||||
|
||||
bool bCreate = !!(txFlags & tfCreateAccount);
|
||||
|
||||
uint160 uCurrency;
|
||||
if (txn.getITFieldPresent(sfCurrency))
|
||||
{
|
||||
uCurrency = txn.getITFieldH160(sfCurrency);
|
||||
if (!uCurrency)
|
||||
{
|
||||
std::cerr << "doPayment: Invalid transaction: " SYSTEM_CURRENCY_CODE " explicitly specified." << std::endl;
|
||||
return tenEXPLICITXNC;
|
||||
}
|
||||
}
|
||||
// XXX Allow ripple to create.
|
||||
|
||||
LedgerStateParms qry = lepNONE;
|
||||
SLE::pointer sleDst = mLedger->getAccountRoot(qry, uDstAccountID);
|
||||
if (!sleDst)
|
||||
{
|
||||
// Destination account does not exist.
|
||||
if (bCreate && !!uCurrency)
|
||||
// XXX Also make sure non-ripple dest if creating.
|
||||
if (bCreate && !saAmount.isNative())
|
||||
{
|
||||
std::cerr << "doPayment: Invalid transaction: Create account may only fund XBC." << std::endl;
|
||||
return tenCREATEXNC;
|
||||
std::cerr << "doPayment: Invalid transaction: Create account may only fund XNS." << std::endl;
|
||||
|
||||
return tenCREATEXNS;
|
||||
}
|
||||
else if (!bCreate)
|
||||
{
|
||||
std::cerr << "doPayment: Delay transaction: Destination account does not exist." << std::endl;
|
||||
|
||||
return terNO_DST;
|
||||
}
|
||||
|
||||
@@ -1066,6 +1069,7 @@ TransactionEngineResult TransactionEngine::doPayment(const SerializedTransaction
|
||||
else if (bCreate)
|
||||
{
|
||||
std::cerr << "doPayment: Invalid transaction: Account already created." << std::endl;
|
||||
|
||||
return terCREATED;
|
||||
}
|
||||
else
|
||||
@@ -1073,28 +1077,68 @@ TransactionEngineResult TransactionEngine::doPayment(const SerializedTransaction
|
||||
accounts.push_back(std::make_pair(taaMODIFY, sleDst));
|
||||
}
|
||||
|
||||
STAmount saAmount = txn.getITFieldAmount(sfAmount);
|
||||
|
||||
if (!uCurrency)
|
||||
if (!bRipple)
|
||||
{
|
||||
STAmount saSrcBalance = accounts[0].second->getIValueFieldAmount(sfBalance);
|
||||
// Direct XNS payment.
|
||||
if (!saAmount.isNative())
|
||||
{
|
||||
std::cerr << "doPayment: Invalid transaction: direct " SYSTEM_CURRENCY_CODE " required." << std::endl;
|
||||
|
||||
return tenDIRECT_XNS_ONLY;
|
||||
}
|
||||
|
||||
if (saSrcBalance < saAmount)
|
||||
{
|
||||
std::cerr << "doPayment: Delay transaction: Insufficent funds." << std::endl;
|
||||
|
||||
return terUNFUNDED;
|
||||
}
|
||||
|
||||
accounts[0].second->setIFieldAmount(sfBalance, saSrcBalance - saAmount);
|
||||
accounts[1].second->setIFieldAmount(sfBalance, accounts[1].second->getIValueFieldAmount(sfBalance) + saAmount);
|
||||
}
|
||||
else
|
||||
{
|
||||
// WRITEME: Handle non-native currencies, paths
|
||||
return tenUNKNOWN;
|
||||
|
||||
return terSUCCESS;
|
||||
}
|
||||
|
||||
return terSUCCESS;
|
||||
//
|
||||
// Try direct ripple first.
|
||||
//
|
||||
|
||||
uint160 uDstCurrency = saAmount.getCurrency();
|
||||
|
||||
qry = lepNONE;
|
||||
SLE::pointer sleRippleState = mLedger->getRippleState(qry, uSrcAccountID, uDstAccountID, uDstCurrency);
|
||||
|
||||
if (sleRippleState)
|
||||
{
|
||||
// There is a direct relationship.
|
||||
|
||||
}
|
||||
|
||||
STPathSet spsPaths = txn.getITFieldPathSet(sfPaths);
|
||||
|
||||
// XXX If we are parsing for determing forwarding check maximum path count.
|
||||
if (!spsPaths.getPathCount())
|
||||
{
|
||||
std::cerr << "doPayment: Invalid transaction: No paths." << std::endl;
|
||||
|
||||
return tenRIPPLE_EMPTY;
|
||||
}
|
||||
#if 0
|
||||
std::vector<STPath> spPath;
|
||||
|
||||
BOOST_FOREACH(std::vector<STPath>& spPath, spsPaths)
|
||||
{
|
||||
|
||||
std::cerr << "doPayment: Implementation error: Not implemented." << std::endl;
|
||||
|
||||
return tenUNKNOWN;
|
||||
}
|
||||
#endif
|
||||
|
||||
std::cerr << "doPayment: Delay transaction: No ripple paths could be satisfied." << std::endl;
|
||||
|
||||
return terBAD_RIPPLE;
|
||||
}
|
||||
|
||||
TransactionEngineResult TransactionEngine::doTransitSet(const SerializedTransaction& st, std::vector<AffectedAccount>&)
|
||||
|
||||
@@ -14,20 +14,23 @@ enum TransactionEngineResult
|
||||
|
||||
// Malformed: Fee claimed
|
||||
tenGEN_IN_USE = -300, // Generator already in use.
|
||||
tenCREATEXNC, // Can not specify non XNC for Create.
|
||||
tenEXPLICITXNC, // XNC is used by default, don't specify it.
|
||||
tenCREATEXNS, // Can not specify non XNS for Create.
|
||||
tenEXPLICITXNS, // XNS is used by default, don't specify it.
|
||||
tenDST_NEEDED, // Destination not specified.
|
||||
tenDST_IS_SRC, // Destination may not be source.
|
||||
tenBAD_GEN_AUTH, // Not authorized to claim generator.
|
||||
tenBAD_ADD_AUTH, // Not authorized to add account.
|
||||
tenBAD_CLAIM_ID, // Malformed.
|
||||
tenBAD_SET_ID, // Malformed.
|
||||
tenDIRECT_XNS_ONLY, // Direct payments are non-ripple XNS only.
|
||||
tenRIPPLE_EMPTY, // PathSet with no paths.
|
||||
|
||||
// Invalid: Ledger won't allow.
|
||||
tenCLAIMED = -200, // Can not claim a previously claimed account.
|
||||
tenCREATED, // Can't add an already created account.
|
||||
tenMSG_SET, // Can't change a message key.
|
||||
tenBAD_AUTH_MASTER, // Auth for unclaimed account needs correct master key.
|
||||
tenBAD_RIPPLE, // Ledger prevents ripple from succeeding.
|
||||
|
||||
// Other
|
||||
tenFAILED = -100, // Something broke horribly
|
||||
@@ -61,6 +64,7 @@ enum TransactionEngineResult
|
||||
terFUNDS_SPENT, // Can't set password, password set funds already spent.
|
||||
terUNCLAIMED, // Can not use an unclaimed account.
|
||||
terBAD_AUTH, // Transaction's public key is not authorized.
|
||||
terBAD_RIPPLE, // No ripple path can be satisfied.
|
||||
};
|
||||
|
||||
enum TransactionEngineParams
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "Application.h"
|
||||
#include "Conversion.h"
|
||||
#include "HttpsClient.h"
|
||||
#include "Log.h"
|
||||
#include "ParseSection.h"
|
||||
#include "Serializer.h"
|
||||
#include "UniqueNodeList.h"
|
||||
@@ -608,12 +609,11 @@ void UniqueNodeList::processIps(const std::string& strSite, const NewcoinAddress
|
||||
{
|
||||
Database* db=theApp->getWalletDB()->getDB();
|
||||
|
||||
std::string strEscNodePublic = db->escape(naNodePublic.humanNodePublic());
|
||||
std::string strEscNodePublic = sqlEscape(naNodePublic.humanNodePublic());
|
||||
|
||||
std::cerr
|
||||
Log(lsINFO)
|
||||
<< str(boost::format("Validator: '%s' processing %d ips.")
|
||||
% strSite % ( pmtVecStrIps ? pmtVecStrIps->size() : 0))
|
||||
<< std::endl;
|
||||
% strSite % ( pmtVecStrIps ? pmtVecStrIps->size() : 0));
|
||||
|
||||
// Remove all current Validator's entries in IpReferrals
|
||||
{
|
||||
@@ -631,32 +631,15 @@ void UniqueNodeList::processIps(const std::string& strSite, const NewcoinAddress
|
||||
int iValues = 0;
|
||||
BOOST_FOREACH(std::string strReferral, *pmtVecStrIps)
|
||||
{
|
||||
boost::smatch smMatch;
|
||||
std::string strIP;
|
||||
int iPort;
|
||||
bool bValid = false;
|
||||
|
||||
if (iValues == REFERRAL_VALIDATORS_MAX)
|
||||
break;
|
||||
|
||||
static boost::regex reEndpoint("\\`\\s*(\\S+)(?:\\s+(\\d+))?\\s*\\'");
|
||||
std::string strIP;
|
||||
int iPort;
|
||||
bool bValid = parseIpPort(strReferral, strIP, iPort);
|
||||
|
||||
// XXX Filter out private network ips.
|
||||
// XXX http://en.wikipedia.org/wiki/Private_network
|
||||
if (boost::regex_match(strReferral, smMatch, reEndpoint))
|
||||
{
|
||||
boost::system::error_code err;
|
||||
std::string strIPRaw = smMatch[1];
|
||||
std::string strPortRaw = smMatch[2];
|
||||
|
||||
iPort = strPortRaw.empty() ? -1 : boost::lexical_cast<int>(strPortRaw);
|
||||
|
||||
boost::asio::ip::address addrIP = boost::asio::ip::address::from_string(strIPRaw, err);
|
||||
|
||||
bValid = !err;
|
||||
if (bValid)
|
||||
strIP = addrIP.to_string();
|
||||
}
|
||||
|
||||
if (bValid)
|
||||
{
|
||||
@@ -733,10 +716,7 @@ int UniqueNodeList::processValidators(const std::string& strSite, const std::str
|
||||
|
||||
if (!boost::regex_match(strReferral, smMatch, reReferral))
|
||||
{
|
||||
std::cerr
|
||||
<< str(boost::format("Validator: '%s' ["SECTION_VALIDATORS"]: rejecting line: '%s'")
|
||||
% strSite % strReferral)
|
||||
<< std::endl;
|
||||
Log(lsWARNING) << str(boost::format("Bad validator: syntax error: %s: %s") % strSite % strReferral);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -744,27 +724,36 @@ int UniqueNodeList::processValidators(const std::string& strSite, const std::str
|
||||
std::string strComment = smMatch[2];
|
||||
NewcoinAddress naValidator;
|
||||
|
||||
std::cerr << str(boost::format("Validator='%s', Comment='%s'") % strRefered % strComment) << std::endl;
|
||||
if (naValidator.setSeedGeneric(strRefered))
|
||||
{
|
||||
|
||||
if (naValidator.setNodePublic(strRefered))
|
||||
Log(lsWARNING) << str(boost::format("Bad validator: domain or public key required: %s %s") % strRefered % strComment);
|
||||
}
|
||||
else if (naValidator.setNodePublic(strRefered))
|
||||
{
|
||||
// A public key.
|
||||
// XXX Schedule for CAS lookup.
|
||||
nodeAddPublic(naValidator, vsWhy, strComment);
|
||||
|
||||
Log(lsINFO) << str(boost::format("Node Public: %s %s") % strRefered % strComment);
|
||||
|
||||
if (naNodePublic.isValid())
|
||||
vstrValues.push_back(str(boost::format("('%s',%d,'%s')") % strNodePublic % iValues % naValidator.humanNodePublic()));
|
||||
|
||||
iValues++;
|
||||
}
|
||||
else
|
||||
{
|
||||
// A domain: need to look it up.
|
||||
nodeAddDomain(strRefered, vsWhy, strComment);
|
||||
|
||||
Log(lsINFO) << str(boost::format("Node Domain: %s %s") % strRefered % strComment);
|
||||
|
||||
if (naNodePublic.isValid())
|
||||
vstrValues.push_back(str(boost::format("('%s',%d,%s)") % strNodePublic % iValues % sqlEscape(strRefered)));
|
||||
}
|
||||
|
||||
iValues++;
|
||||
iValues++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -904,7 +893,7 @@ void UniqueNodeList::responseFetch(const std::string strDomain, const boost::sys
|
||||
else
|
||||
{
|
||||
std::cerr
|
||||
<< boost::format("Validator: '%s' unabile to retrieve " NODE_FILE_NAME ": %s")
|
||||
<< boost::format("Validator: '%s' unable to retrieve " NODE_FILE_NAME ": %s")
|
||||
% strDomain
|
||||
% err.message()
|
||||
<< std::endl;
|
||||
@@ -1140,8 +1129,10 @@ int UniqueNodeList::iSourceScore(validatorSource vsWhy)
|
||||
|
||||
switch (vsWhy) {
|
||||
case vsConfig: iScore = 1500; break;
|
||||
case vsInbound: iScore = 0; break;
|
||||
case vsManual: iScore = 1500; break;
|
||||
case vsReferral: iScore = 0; break;
|
||||
case vsTold: iScore = 0; break;
|
||||
case vsValidator: iScore = 1000; break;
|
||||
case vsWeb: iScore = 200; break;
|
||||
default:
|
||||
@@ -1222,7 +1213,7 @@ void UniqueNodeList::setSeedDomains(const seedDomain& sdSource, bool bNext)
|
||||
std::string strSql = str(boost::format("REPLACE INTO SeedDomains (Domain,PublicKey,Source,Next,Scan,Fetch,Sha256,Comment) VALUES (%s, %s, %s, %d, %d, %d, '%s', %s);")
|
||||
% db->escape(sdSource.strDomain)
|
||||
% (sdSource.naPublicKey.isValid() ? db->escape(sdSource.naPublicKey.humanNodePublic()) : "NULL")
|
||||
% db->escape(std::string(1, static_cast<char>(sdSource.vsSource)))
|
||||
% sqlEscape(std::string(1, static_cast<char>(sdSource.vsSource)))
|
||||
% iNext
|
||||
% iScan
|
||||
% iFetch
|
||||
@@ -1567,12 +1558,11 @@ void UniqueNodeList::nodeNetwork()
|
||||
|
||||
void UniqueNodeList::nodeBootstrap()
|
||||
{
|
||||
int iDomains = 0;
|
||||
int iNodes = 0;
|
||||
int iDomains = 0;
|
||||
int iNodes = 0;
|
||||
Database* db = theApp->getWalletDB()->getDB();
|
||||
|
||||
{
|
||||
Database* db=theApp->getWalletDB()->getDB();
|
||||
|
||||
ScopedLock sl(theApp->getWalletDB()->getDBLock());
|
||||
|
||||
if (db->executeSQL(str(boost::format("SELECT COUNT(*) AS Count FROM SeedDomains WHERE Source='%s' OR Source='%c';") % vsManual % vsValidator)) && db->startIterRows())
|
||||
@@ -1587,7 +1577,7 @@ void UniqueNodeList::nodeBootstrap()
|
||||
// Always merge in the file specified in the config.
|
||||
if (!theConfig.UNL_DEFAULT.empty())
|
||||
{
|
||||
std::cerr << "Bootstrapping UNL: loading from unl_default." << std::endl;
|
||||
Log(lsINFO) << "Bootstrapping UNL: loading from unl_default.";
|
||||
|
||||
bLoaded = nodeLoad(theConfig.UNL_DEFAULT);
|
||||
}
|
||||
@@ -1595,7 +1585,7 @@ void UniqueNodeList::nodeBootstrap()
|
||||
// If never loaded anything try the current directory.
|
||||
if (!bLoaded && theConfig.UNL_DEFAULT.empty())
|
||||
{
|
||||
std::cerr << "Bootstrapping UNL: loading from '" VALIDATORS_FILE_NAME "'." << std::endl;
|
||||
Log(lsINFO) << "Bootstrapping UNL: loading from '" VALIDATORS_FILE_NAME "'.";
|
||||
|
||||
bLoaded = nodeLoad(VALIDATORS_FILE_NAME);
|
||||
}
|
||||
@@ -1605,7 +1595,7 @@ void UniqueNodeList::nodeBootstrap()
|
||||
{
|
||||
NewcoinAddress naInvalid; // Don't want a referrer on added entries.
|
||||
|
||||
std::cerr << "Bootstrapping UNL: loading from " CONFIG_FILE_NAME "." << std::endl;
|
||||
Log(lsINFO) << "Bootstrapping UNL: loading from " CONFIG_FILE_NAME ".";
|
||||
|
||||
if (processValidators("local", CONFIG_FILE_NAME, naInvalid, vsConfig, &theConfig.VALIDATORS))
|
||||
bLoaded = true;
|
||||
@@ -1613,10 +1603,40 @@ void UniqueNodeList::nodeBootstrap()
|
||||
|
||||
if (!bLoaded)
|
||||
{
|
||||
std::cerr << "Bootstrapping UNL: loading from " << theConfig.VALIDATORS_SITE << "." << std::endl;
|
||||
Log(lsINFO) << "Bootstrapping UNL: loading from " << theConfig.VALIDATORS_SITE << ".";
|
||||
|
||||
nodeNetwork();
|
||||
}
|
||||
|
||||
if (!theConfig.IPS.empty())
|
||||
{
|
||||
std::vector<std::string> vstrValues;
|
||||
|
||||
vstrValues.reserve(theConfig.IPS.size());
|
||||
|
||||
BOOST_FOREACH(const std::string& strPeer, theConfig.IPS)
|
||||
{
|
||||
std::string strIP;
|
||||
int iPort;
|
||||
|
||||
if (parseIpPort(strPeer, strIP, iPort))
|
||||
{
|
||||
vstrValues.push_back(str(boost::format("(%s,'%c')")
|
||||
% sqlEscape(str(boost::format("%s %d") % strIP % iPort))
|
||||
% static_cast<char>(vsConfig)));
|
||||
}
|
||||
}
|
||||
|
||||
if (!vstrValues.empty())
|
||||
{
|
||||
ScopedLock sl(theApp->getWalletDB()->getDBLock());
|
||||
|
||||
db->executeSQL(str(boost::format("REPLACE INTO PeerIps (IpPort,Source) VALUES %s;")
|
||||
% strJoin(vstrValues.begin(), vstrValues.end(), ",")));
|
||||
}
|
||||
|
||||
fetchDirty();
|
||||
}
|
||||
}
|
||||
|
||||
// Process a validators.txt.
|
||||
|
||||
@@ -33,8 +33,10 @@ class UniqueNodeList
|
||||
public:
|
||||
typedef enum {
|
||||
vsConfig = 'C', // newcoind.cfg
|
||||
vsInbound = 'I',
|
||||
vsManual = 'M',
|
||||
vsReferral = 'R',
|
||||
vsTold = 'T',
|
||||
vsValidator = 'V', // validators.txt
|
||||
vsWeb = 'W',
|
||||
} validatorSource;
|
||||
@@ -92,7 +94,6 @@ private:
|
||||
void trustedLoad();
|
||||
|
||||
bool scoreRound(std::vector<scoreNode>& vsnNodes);
|
||||
int iSourceScore(validatorSource vsWhy);
|
||||
|
||||
void responseFetch(const std::string strDomain, const boost::system::error_code& err, const std::string strSiteFile);
|
||||
|
||||
@@ -156,6 +157,8 @@ public:
|
||||
void nodeNetwork();
|
||||
|
||||
Json::Value getUnlJson();
|
||||
|
||||
int iSourceScore(validatorSource vsWhy);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -2,22 +2,41 @@
|
||||
#include "ValidationCollection.h"
|
||||
|
||||
#include "Application.h"
|
||||
#include "LedgerTiming.h"
|
||||
#include "Log.h"
|
||||
|
||||
bool ValidationCollection::addValidation(SerializedValidation::pointer val)
|
||||
{
|
||||
if(theApp->getUNL().nodeInUNL(val->getSignerPublic()))
|
||||
bool isCurrent = false;
|
||||
if (theApp->getUNL().nodeInUNL(val->getSignerPublic()))
|
||||
{
|
||||
val->setTrusted();
|
||||
uint64 now = theApp->getOPs().getNetworkTimeNC();
|
||||
uint64 valClose = val->getCloseTime();
|
||||
if ((now > valClose) && (now < (valClose + LEDGER_INTERVAL)))
|
||||
isCurrent = true;
|
||||
else
|
||||
Log(lsWARNING) << "Received stale validation now=" << now << ", close=" << valClose;
|
||||
}
|
||||
|
||||
uint256 hash = val->getLedgerHash();
|
||||
uint160 node = val->getSignerPublic().getNodeID();
|
||||
|
||||
boost::mutex::scoped_lock sl(mValidationLock);
|
||||
bool ret = mValidations[hash].insert(std::make_pair(node, val)).second;
|
||||
if (ret)
|
||||
Log(lsINFO) << "Val for " << hash.GetHex() << " from " << node.GetHex() << " added " <<
|
||||
(val->isTrusted() ? "trusted" : "UNtrusted");
|
||||
return ret;
|
||||
{
|
||||
boost::mutex::scoped_lock sl(mValidationLock);
|
||||
if (!mValidations[hash].insert(std::make_pair(node, val)).second)
|
||||
return false;
|
||||
if (isCurrent)
|
||||
{
|
||||
boost::unordered_map<uint160, SerializedValidation::pointer>::iterator it = mCurrentValidations.find(node);
|
||||
if ((it == mCurrentValidations.end()) || (val->getCloseTime() >= it->second->getCloseTime()))
|
||||
mCurrentValidations[node] = val;
|
||||
}
|
||||
}
|
||||
|
||||
Log(lsINFO) << "Val for " << hash.GetHex() << " from " << val->getSignerPublic().humanNodePublic()
|
||||
<< " added " << (val->isTrusted() ? "trusted" : "UNtrusted");
|
||||
return true;
|
||||
}
|
||||
|
||||
ValidationSet ValidationCollection::getValidations(const uint256& ledger)
|
||||
@@ -31,20 +50,54 @@ ValidationSet ValidationCollection::getValidations(const uint256& ledger)
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ValidationCollection::getValidationCount(const uint256& ledger, int& trusted, int &untrusted)
|
||||
void ValidationCollection::getValidationCount(const uint256& ledger, bool currentOnly, int& trusted, int &untrusted)
|
||||
{
|
||||
trusted = untrusted = 0;
|
||||
boost::mutex::scoped_lock sl(mValidationLock);
|
||||
boost::unordered_map<uint256, ValidationSet>::iterator it = mValidations.find(ledger);
|
||||
uint64 now = theApp->getOPs().getNetworkTimeNC();
|
||||
if (it != mValidations.end())
|
||||
{
|
||||
for (ValidationSet::iterator vit = it->second.begin(), end = it->second.end();
|
||||
vit != end; ++vit)
|
||||
for (ValidationSet::iterator vit = it->second.begin(), end = it->second.end(); vit != end; ++vit)
|
||||
{
|
||||
if(vit->second->isTrusted())
|
||||
bool trusted = vit->second->isTrusted();
|
||||
if (trusted && currentOnly)
|
||||
{
|
||||
uint64 closeTime = vit->second->getCloseTime();
|
||||
if ((now < closeTime) || (now > (closeTime + 2 * LEDGER_INTERVAL)))
|
||||
trusted = false;
|
||||
}
|
||||
if (trusted)
|
||||
++trusted;
|
||||
else
|
||||
++untrusted;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
boost::unordered_map<uint256, int> ValidationCollection::getCurrentValidations()
|
||||
{
|
||||
uint64 now = theApp->getOPs().getNetworkTimeNC();
|
||||
boost::unordered_map<uint256, int> ret;
|
||||
|
||||
{
|
||||
boost::mutex::scoped_lock sl(mValidationLock);
|
||||
boost::unordered_map<uint160, SerializedValidation::pointer>::iterator it = mCurrentValidations.begin();
|
||||
while (it != mCurrentValidations.end())
|
||||
{
|
||||
if (now > (it->second->getCloseTime() + LEDGER_INTERVAL))
|
||||
{
|
||||
Log(lsTRACE) << "Erasing validation for " << it->second->getLedgerHash().GetHex();
|
||||
it = mCurrentValidations.erase(it);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log(lsTRACE) << "Counting validation for " << it->second->getLedgerHash().GetHex();
|
||||
++ret[it->second->getLedgerHash()];
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -16,13 +16,15 @@ class ValidationCollection
|
||||
|
||||
boost::mutex mValidationLock;
|
||||
boost::unordered_map<uint256, ValidationSet> mValidations;
|
||||
boost::unordered_map<uint160, SerializedValidation::pointer> mCurrentValidations;
|
||||
|
||||
public:
|
||||
ValidationCollection() { ; }
|
||||
|
||||
bool addValidation(SerializedValidation::pointer);
|
||||
ValidationSet getValidations(const uint256& ledger);
|
||||
void getValidationCount(const uint256& ledger, int& trusted, int& untrusted);
|
||||
void getValidationCount(const uint256& ledger, bool currentOnly, int& trusted, int& untrusted);
|
||||
boost::unordered_map<uint256, int> getCurrentValidations();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -88,6 +88,7 @@ enum NodeEvent {
|
||||
neCLOSING_LEDGER = 1; // closing a ledger because its close time has come
|
||||
neACCEPTED_LEDGER = 2; // accepting a closed ledger, we have finished computing it
|
||||
neSWITCHED_LEDGER = 3; // changing due to network consensus
|
||||
neLOST_SYNC = 4;
|
||||
}
|
||||
|
||||
message TMStatusChange {
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include "RPC.h"
|
||||
#include "BitcoinUtil.h"
|
||||
#include "Config.h"
|
||||
#include "Log.h"
|
||||
|
||||
using namespace boost;
|
||||
using namespace boost::asio;
|
||||
@@ -71,7 +72,7 @@ std::string rfc1123Time()
|
||||
|
||||
std::string HTTPReply(int nStatus, const std::string& strMsg)
|
||||
{
|
||||
std::cout << "HTTP Reply " << nStatus << " " << strMsg << std::endl;
|
||||
Log(lsTRACE) << "HTTP Reply " << nStatus << " " << strMsg;
|
||||
|
||||
if (nStatus == 401)
|
||||
return strprintf("HTTP/1.0 401 Authorization Required\r\n"
|
||||
|
||||
@@ -511,8 +511,6 @@ public:
|
||||
zero();
|
||||
}
|
||||
}
|
||||
|
||||
base_uint160 to160() const;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
#include "utils.h"
|
||||
#include "uint256.h"
|
||||
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/regex.hpp>
|
||||
|
||||
//
|
||||
// Time support
|
||||
// We have our own epoch.
|
||||
@@ -123,6 +126,36 @@ DH* DH_der_load(const std::string& strDer)
|
||||
return d2i_DHparams(NULL, &pbuf, strDer.size());
|
||||
}
|
||||
|
||||
//
|
||||
// IP Port parsing
|
||||
//
|
||||
// <-- iPort: "" = -1
|
||||
bool parseIpPort(const std::string& strSource, std::string& strIP, int& iPort)
|
||||
{
|
||||
boost::smatch smMatch;
|
||||
bool bValid = false;
|
||||
|
||||
static boost::regex reEndpoint("\\`\\s*(\\S+)(?:\\s+(\\d+))?\\s*\\'");
|
||||
|
||||
if (boost::regex_match(strSource, smMatch, reEndpoint))
|
||||
{
|
||||
boost::system::error_code err;
|
||||
std::string strIPRaw = smMatch[1];
|
||||
std::string strPortRaw = smMatch[2];
|
||||
|
||||
boost::asio::ip::address addrIP = boost::asio::ip::address::from_string(strIPRaw, err);
|
||||
|
||||
bValid = !err;
|
||||
if (bValid)
|
||||
{
|
||||
strIP = addrIP.to_string();
|
||||
iPort = strPortRaw.empty() ? -1 : boost::lexical_cast<int>(strPortRaw);
|
||||
}
|
||||
}
|
||||
|
||||
return bValid;
|
||||
}
|
||||
|
||||
/*
|
||||
void intIPtoStr(int ip,std::string& retStr)
|
||||
{
|
||||
@@ -130,7 +163,7 @@ void intIPtoStr(int ip,std::string& retStr)
|
||||
bytes[0] = ip & 0xFF;
|
||||
bytes[1] = (ip >> 8) & 0xFF;
|
||||
bytes[2] = (ip >> 16) & 0xFF;
|
||||
bytes[3] = (ip >> 24) & 0xFF;
|
||||
bytes[3] = (ip >> 24) & 0xFF;
|
||||
|
||||
retStr=str(boost::format("%d.%d.%d.%d") % bytes[3] % bytes[2] % bytes[1] % bytes[0] );
|
||||
}
|
||||
@@ -145,7 +178,7 @@ int strIPtoInt(std::string& ipStr)
|
||||
#include <winsock2.h>
|
||||
|
||||
//#include "Winsock2.h"
|
||||
//#include <windows.h>
|
||||
//#include <windows.h>
|
||||
// from: http://stackoverflow.com/questions/3022552/is-there-any-standard-htonl-like-function-for-64-bits-integers-in-c
|
||||
// but we don't need to check the endianness
|
||||
uint64_t htobe64(uint64_t value)
|
||||
|
||||
12
src/utils.h
12
src/utils.h
@@ -8,9 +8,11 @@
|
||||
|
||||
#include "types.h"
|
||||
|
||||
#define nothing() do {} while (0)
|
||||
#define fallthru() do {} while (0)
|
||||
#define NUMBER(x) (sizeof(x)/sizeof((x)[0]))
|
||||
#define nothing() do {} while (0)
|
||||
#define fallthru() do {} while (0)
|
||||
#define NUMBER(x) (sizeof(x)/sizeof((x)[0]))
|
||||
#define ADDRESS(p) strHex(uint64( ((char*) p) - ((char*) 0)))
|
||||
#define ADDRESS_SHARED(p) strHex(uint64( ((char*) (p).get()) - ((char*) 0)))
|
||||
|
||||
#ifndef MAX
|
||||
#define MAX(x,y) ((x) < (y) ? (y) : (x))
|
||||
@@ -36,7 +38,7 @@ int strIPtoInt(std::string& ipStr);
|
||||
template<class Iterator>
|
||||
std::string strJoin(Iterator first, Iterator last, std::string strSeperator)
|
||||
{
|
||||
std::ostringstream ossValues;
|
||||
std::ostringstream ossValues;
|
||||
|
||||
for (Iterator start = first; first != last; first++)
|
||||
{
|
||||
@@ -104,6 +106,8 @@ std::vector<unsigned char> strUnHex(const std::string& strSrc);
|
||||
std::vector<unsigned char> strCopy(const std::string& strSrc);
|
||||
std::string strCopy(const std::vector<unsigned char>& vucSrc);
|
||||
|
||||
bool parseIpPort(const std::string& strSource, std::string& strIP, int& iPort);
|
||||
|
||||
DH* DH_der_load(const std::string& strDer);
|
||||
std::string DH_der_gen(int iKeyLength);
|
||||
|
||||
|
||||
@@ -9,9 +9,9 @@
|
||||
# All other lines should be hankos or domain names.
|
||||
#
|
||||
# [validators]:
|
||||
# List of nodes to accept as validators speficied by public key or domain.
|
||||
# List of nodes to accept as validators specified by public key or domain.
|
||||
#
|
||||
# For domains, newcoind will probe for https web servers at the specied
|
||||
# For domains, newcoind will probe for https web servers at the specified
|
||||
# domain in the following order: newcoin.DOMAIN, www.DOMAIN, DOMAIN
|
||||
#
|
||||
# Examples: redstem.com
|
||||
@@ -23,3 +23,4 @@
|
||||
n9LQC4xFSWXNv1SU1sKtjrW6TZpBZSwp1nRWej8saGs155x42YFZ first
|
||||
n9LFzWuhKNvXStHAuemfRKFVECLApowncMAM5chSCL9R5ECHGN4V second
|
||||
n9KXAZxiHkWuVGxDEE8boW7WmcycpZNmWei4vxVaywLZ391Nbuqx third
|
||||
n94365hzFKikgCULeJwczs3kwzpir3KVHkfhUWGT4MjmbEbC5xBy
|
||||
Reference in New Issue
Block a user