From 3cb3b41ceff88ad31e39a9734b227f3ff9cf7fad Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Tue, 20 Nov 2012 13:13:52 -0800 Subject: [PATCH 01/11] Rename unl_default to validators_file. --- rippled-example.cfg | 146 ++++++++++++++++++++++++++++++ src/cpp/ripple/Config.cpp | 6 +- src/cpp/ripple/Config.h | 2 +- src/cpp/ripple/RPCHandler.cpp | 2 +- src/cpp/ripple/UniqueNodeList.cpp | 6 +- 5 files changed, 154 insertions(+), 8 deletions(-) create mode 100644 rippled-example.cfg diff --git a/rippled-example.cfg b/rippled-example.cfg new file mode 100644 index 000000000..a57fa3a8c --- /dev/null +++ b/rippled-example.cfg @@ -0,0 +1,146 @@ +# +# Sample rippled.cfg +# +# This file contains configuration information for rippled. +# +# This file should be named rippled.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 rippled, it will attempt to find this file. For details, +# refer to the manual page for --conf command line option. +# +# [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: ripple.com +# +# [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 rippled +# starts up, if the databases are missing or are obsolete due to an upgrade +# of rippled, rippled will reconstruct the UNL list as specified here. +# +# If this entry is not present or empty, rippled will look for a validators.txt in the +# config directory. If not found there, it will attempt to retrieve the file +# from the Ripple 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/ripple/validators.txt +# /home/johndoe/ripple/validators.txt +# +# [validators]: +# Only valid in "rippled.cfg", "ripple.txt", and the referered [validators_url]. +# List of nodes to accept as validators speficied by public key or domain. +# +# For domains, rippled will probe for https web servers at the specied +# domain in the following order: ripple.DOMAIN, www.DOMAIN, DOMAIN +# +# Examples: +# redstem.com +# n9KorY8QtTdRx7TVDpwnG9NvyxsDwHUKUEeDLY3AkiGncVaSXZi5 +# n9MqiExBcoG19UXwoLjBJnhsxEhAZMuWwJDRdkyDz1EkEkwzQTNt John Doe +# +# [ips]: +# Only valid in "rippled.cfg", "ripple.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 +# +# [sntp_servers] +# IP address or domain of servers to use for time synchronization. +# The default time servers are suitable for servers located in the United States +# +# [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 + +[websocket_ip] +0.0.0.0 + +[websocket_port] +5006 + +[debug_logfile] +log/debug.log + +[sntp_servers] +time.windows.com +time.apple.com +time.nist.gov +pool.ntp.org + +[validation_seed] +shh1D4oj5czH3PUEjYES8c7Bay3tE + +[unl_default] +validators.txt + +[ips] +23.21.167.100 51235 +23.23.201.55 51235 +107.21.116.214 51235 diff --git a/src/cpp/ripple/Config.cpp b/src/cpp/ripple/Config.cpp index 8a665ff13..68f2e3192 100644 --- a/src/cpp/ripple/Config.cpp +++ b/src/cpp/ripple/Config.cpp @@ -27,7 +27,7 @@ #define SECTION_RPC_IP "rpc_ip" #define SECTION_RPC_PORT "rpc_port" #define SECTION_SNTP "sntp_servers" -#define SECTION_UNL_DEFAULT "unl_default" +#define SECTION_VALIDATORS_FILE "validators_file" #define SECTION_VALIDATION_QUORUM "validation_quorum" #define SECTION_VALIDATION_SEED "validation_seed" #define SECTION_WEBSOCKET_PUBLIC_IP "websocket_public_ip" @@ -292,8 +292,8 @@ void Config::load() if (sectionSingleB(secConfig, SECTION_ACCOUNT_PROBE_MAX, strTemp)) ACCOUNT_PROBE_MAX = boost::lexical_cast(strTemp); - if (sectionSingleB(secConfig, SECTION_UNL_DEFAULT, strTemp)) - UNL_DEFAULT = strTemp; + if (sectionSingleB(secConfig, SECTION_VALIDATORS_FILE, strTemp)) + VALIDATORS_FILE = strTemp; if (sectionSingleB(secConfig, SECTION_DEBUG_LOGFILE, strTemp)) DEBUG_LOGFILE = strTemp; diff --git a/src/cpp/ripple/Config.h b/src/cpp/ripple/Config.h index 3807b51df..199b4292e 100644 --- a/src/cpp/ripple/Config.h +++ b/src/cpp/ripple/Config.h @@ -50,7 +50,7 @@ public: boost::filesystem::path CONFIG_DIR; boost::filesystem::path DATA_DIR; boost::filesystem::path DEBUG_LOGFILE; - boost::filesystem::path UNL_DEFAULT; + boost::filesystem::path VALIDATORS_FILE; std::string VALIDATORS_SITE; // Where to find validators.txt on the Internet. std::vector VALIDATORS; // Validators from rippled.cfg. diff --git a/src/cpp/ripple/RPCHandler.cpp b/src/cpp/ripple/RPCHandler.cpp index ba9f6f78b..6d6a4595e 100644 --- a/src/cpp/ripple/RPCHandler.cpp +++ b/src/cpp/ripple/RPCHandler.cpp @@ -1638,7 +1638,7 @@ Json::Value RPCHandler::doUnlList(const Json::Value& params) // Populate the UNL from a local validators.txt file. Json::Value RPCHandler::doUnlLoad(const Json::Value& params) { - if (theConfig.UNL_DEFAULT.empty() || !theApp->getUNL().nodeLoad(theConfig.UNL_DEFAULT)) + if (theConfig.VALIDATORS_FILE.empty() || !theApp->getUNL().nodeLoad(theConfig.VALIDATORS_FILE)) { return rpcError(rpcLOAD_FAILED); } diff --git a/src/cpp/ripple/UniqueNodeList.cpp b/src/cpp/ripple/UniqueNodeList.cpp index f372fcba7..9b9c55a5d 100644 --- a/src/cpp/ripple/UniqueNodeList.cpp +++ b/src/cpp/ripple/UniqueNodeList.cpp @@ -1576,15 +1576,15 @@ void UniqueNodeList::nodeBootstrap() bool bLoaded = iDomains || iNodes; // Always merge in the file specified in the config. - if (!theConfig.UNL_DEFAULT.empty()) + if (!theConfig.VALIDATORS_FILE.empty()) { cLog(lsINFO) << "Bootstrapping UNL: loading from unl_default."; - bLoaded = nodeLoad(theConfig.UNL_DEFAULT); + bLoaded = nodeLoad(theConfig.VALIDATORS_FILE); } // If never loaded anything try the current directory. - if (!bLoaded && theConfig.UNL_DEFAULT.empty()) + if (!bLoaded && theConfig.VALIDATORS_FILE.empty()) { cLog(lsINFO) << "Bootstrapping UNL: loading from '" VALIDATORS_FILE_NAME "'."; From 97c577e5b222c8018cb53a8063d9c993ef0c46de Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Tue, 20 Nov 2012 13:14:45 -0800 Subject: [PATCH 02/11] Fix compiler warning. --- src/cpp/ripple/Transactor.cpp | 30 +++++++++++++----------------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/src/cpp/ripple/Transactor.cpp b/src/cpp/ripple/Transactor.cpp index 1157bf8c2..01861525f 100644 --- a/src/cpp/ripple/Transactor.cpp +++ b/src/cpp/ripple/Transactor.cpp @@ -15,11 +15,11 @@ Transactor::pointer Transactor::makeTransactor(const SerializedTransaction& txn, { switch(txn.getTxnType()) { - case ttPAYMENT: + case ttPAYMENT: return( Transactor::pointer(new PaymentTransactor(txn,params,engine)) ); - case ttACCOUNT_SET: + case ttACCOUNT_SET: return( Transactor::pointer(new AccountSetTransactor(txn,params,engine)) ); - case ttREGULAR_KEY_SET: + case ttREGULAR_KEY_SET: return( Transactor::pointer(new RegularKeySetTransactor(txn,params,engine)) ); case ttTRUST_SET: return( Transactor::pointer(new TrustSetTransactor(txn,params,engine)) ); @@ -35,14 +35,11 @@ Transactor::pointer Transactor::makeTransactor(const SerializedTransaction& txn, } -Transactor::Transactor(const SerializedTransaction& txn,TransactionEngineParams params, TransactionEngine* engine) : mTxn(txn), mParams(params), mEngine(engine) +Transactor::Transactor(const SerializedTransaction& txn,TransactionEngineParams params, TransactionEngine* engine) : mTxn(txn), mEngine(engine), mParams(params) { mHasAuthKey=false; } - - - void Transactor::calculateFee() { mFeeDue = theConfig.FEE_DEFAULT; @@ -61,7 +58,7 @@ TER Transactor::payFee() } if( !saPaid ) return tesSUCCESS; - + // Deduct the fee, so it's not available during the transaction. // Will only write the account back, if the transaction succeeds. if (mSourceBalance < saPaid) @@ -73,12 +70,11 @@ TER Transactor::payFee() return terINSUF_FEE_B; } - + mSourceBalance -= saPaid; mTxnAccount->setFieldAmount(sfBalance, mSourceBalance); - - return tesSUCCESS; + return tesSUCCESS; } @@ -108,7 +104,7 @@ TER Transactor::checkSig() return temBAD_AUTH_MASTER; } - + return tesSUCCESS; } @@ -133,11 +129,10 @@ TER Transactor::checkSeq() if (mEngine->getLedger()->hasTransaction(txID)) return tefALREADY; } - + cLog(lsWARNING) << "applyTransaction: past sequence number"; return tefPAST_SEQ; - }else { mTxnAccount->setFieldU32(sfSequence, t_seq + 1); @@ -209,12 +204,13 @@ TER Transactor::apply() terResult=checkSig(); if(terResult != tesSUCCESS) return(terResult); - + terResult=checkSeq(); if(terResult != tesSUCCESS) return(terResult); mEngine->entryModify(mTxnAccount); return doApply(); - -} \ No newline at end of file +} + +// vim:ts=4 From 17a6b79ed98a32533ad62430d63b15858392d511 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Tue, 20 Nov 2012 13:15:14 -0800 Subject: [PATCH 03/11] Rename example files. --- ripple.txt => ripple-example.txt | 0 rippled.cfg | 145 ----------------------- validators.txt => validators-example.txt | 0 3 files changed, 145 deletions(-) rename ripple.txt => ripple-example.txt (100%) delete mode 100644 rippled.cfg rename validators.txt => validators-example.txt (100%) diff --git a/ripple.txt b/ripple-example.txt similarity index 100% rename from ripple.txt rename to ripple-example.txt diff --git a/rippled.cfg b/rippled.cfg deleted file mode 100644 index c86e2324b..000000000 --- a/rippled.cfg +++ /dev/null @@ -1,145 +0,0 @@ -# -# Sample rippled.cfg -# -# This file should be named rippled.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 rippled, it will attempt to find this file. For details, -# refer to the manual page for --conf command line option. -# -# [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: ripple.com -# -# [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 rippled -# starts up, if the databases are missing or are obsolete due to an upgrade -# of rippled, rippled will reconstruct the UNL list as specified here. -# -# If this entry is not present or empty, rippled will look for a validators.txt in the -# config directory. If not found there, it will attempt to retrieve the file -# from the Ripple 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/ripple/validators.txt -# /home/johndoe/ripple/validators.txt -# -# [validators]: -# Only valid in "rippled.cfg", "ripple.txt", and the referered [validators_url]. -# List of nodes to accept as validators speficied by public key or domain. -# -# For domains, rippled will probe for https web servers at the specied -# domain in the following order: ripple.DOMAIN, www.DOMAIN, DOMAIN -# -# Examples: -# redstem.com -# n9KorY8QtTdRx7TVDpwnG9NvyxsDwHUKUEeDLY3AkiGncVaSXZi5 -# n9MqiExBcoG19UXwoLjBJnhsxEhAZMuWwJDRdkyDz1EkEkwzQTNt John Doe -# -# [ips]: -# Only valid in "rippled.cfg", "ripple.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 -# -# [sntp_servers] -# IP address or domain of servers to use for time synchronization. -# The default time servers are suitable for servers located in the United States -# -# [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 - -[websocket_ip] -0.0.0.0 - -[websocket_port] -5006 - -[debug_logfile] -log/debug.log - -[sntp_servers] -time.windows.com -time.apple.com -time.nist.gov -pool.ntp.org - -[validation_seed] -shh1D4oj5czH3PUEjYES8c7Bay3tE - -[unl_default] -validators.txt - -[ips] -23.21.167.100 51235 -23.23.201.55 51235 -107.21.116.214 51235 diff --git a/validators.txt b/validators-example.txt similarity index 100% rename from validators.txt rename to validators-example.txt From a014bc5843c87ae5cfce38ae605adffa01ea4de5 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Tue, 20 Nov 2012 14:03:48 -0800 Subject: [PATCH 04/11] Build tags in base directory for editors. --- .gitignore | 1 + SConstruct | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 5053c37ba..85a6c74ba 100644 --- a/.gitignore +++ b/.gitignore @@ -15,6 +15,7 @@ # Ignore object files. *.o build +tags # Ignore locally installed node_modules node_modules diff --git a/SConstruct b/SConstruct index 63c2f5ac8..458f48c94 100644 --- a/SConstruct +++ b/SConstruct @@ -132,7 +132,7 @@ for file in RIPPLE_SRCS: rippled = env.Program('build/rippled', RIPPLE_OBJS) -tags = env.CTags('build/obj/tags', RIPPLE_SRCS) +tags = env.CTags('tags', RIPPLE_SRCS) Default(rippled, tags) From 0f010f04452e15373b7c1b64524fbf1897add5ab Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Tue, 20 Nov 2012 14:23:10 -0800 Subject: [PATCH 05/11] Close a loophole where someone requests a large number of proofs of work while they're very easy and then has unlimited use of our system for several minutes because they can keep turning in the easy proofs of work, causing us to keep raising the proof of work level to insane levels. --- src/cpp/ripple/ProofOfWork.cpp | 42 +++++++++++++++++++++++++++------- src/cpp/ripple/ProofOfWork.h | 2 ++ 2 files changed, 36 insertions(+), 8 deletions(-) diff --git a/src/cpp/ripple/ProofOfWork.cpp b/src/cpp/ripple/ProofOfWork.cpp index 724362059..c550a9749 100644 --- a/src/cpp/ripple/ProofOfWork.cpp +++ b/src/cpp/ripple/ProofOfWork.cpp @@ -109,12 +109,9 @@ bool ProofOfWork::checkSolution(const uint256& solution) const return getSHA512Half(buf2) <= mTarget; } -ProofOfWorkGenerator::ProofOfWorkGenerator() : - mIterations(128), - mTarget("0003FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"), - mLastDifficultyChange(time(NULL)), - mValidTime(180) +ProofOfWorkGenerator::ProofOfWorkGenerator() : mValidTime(180) { + setDifficulty(1); RAND_bytes(mSecret.begin(), mSecret.size()); } @@ -162,6 +159,8 @@ POWResult ProofOfWorkGenerator::checkProof(const std::string& token, const uint2 time_t t = lexical_cast_s(fields[3]); time_t now = time(NULL); + int iterations = lexical_cast_s(fields[2]); + { boost::mutex::scoped_lock sl(mLock); if ((t * 4) > (now + mValidTime)) @@ -169,10 +168,15 @@ POWResult ProofOfWorkGenerator::checkProof(const std::string& token, const uint2 cLog(lsDEBUG) << "PoW " << token << " has expired"; return powEXPIRED; } + + if (((iterations != mIterations) || (target != mTarget)) && getPowEntry(target, iterations) < (mPowEntry - 2)) + { // difficulty has increased more than two times since PoW requested + cLog(lsINFO) << "Difficulty has increased since PoW requested"; + return powTOOEASY; + } } - - ProofOfWork pow(token, lexical_cast_s(fields[2]), challenge, target); + ProofOfWork pow(token, iterations, challenge, target); if (!pow.checkSolution(solution)) { cLog(lsDEBUG) << "PoW " << token << " has a bad nonce"; @@ -181,7 +185,6 @@ POWResult ProofOfWorkGenerator::checkProof(const std::string& token, const uint2 { boost::mutex::scoped_lock sl(mLock); -// if (...) return powTOOEASY; if (!mSolvedChallenges.insert(powMap_vt(now, challenge)).second) { cLog(lsDEBUG) << "PoW " << token << " has been reused"; @@ -208,6 +211,16 @@ void ProofOfWorkGenerator::sweep() } while(1); } +void ProofOfWorkGenerator::loadHigh() +{ + // WRITEME +} + +void ProofOfWorkGenerator::loadLow() +{ + // WRITEME +} + struct PowEntry { const char *target; @@ -256,6 +269,19 @@ PowEntry PowEntries[31] = { "00003FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 262144}, // 77309411328, 8 MB }; +int ProofOfWorkGenerator::getPowEntry(const uint256& target, int iterations) +{ + for (int i = 0; i < 31; ++i) + if (PowEntries[i].iterations == iterations) + { + uint256 t; + t.SetHex(PowEntries[i].target); + if (t == target) + return i; + } + return -1; +} + void ProofOfWorkGenerator::setDifficulty(int i) { assert((i >= 0) && (i <= 30)); diff --git a/src/cpp/ripple/ProofOfWork.h b/src/cpp/ripple/ProofOfWork.h index 3d88ffd19..7c77f8659 100644 --- a/src/cpp/ripple/ProofOfWork.h +++ b/src/cpp/ripple/ProofOfWork.h @@ -78,6 +78,8 @@ public: void loadHigh(); void loadLow(); void sweep(void); + + static int getPowEntry(const uint256& target, int iterations); }; #endif From ea00a2d0d06d1afbeec650f416b6fc8df78f4510 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Tue, 20 Nov 2012 14:47:55 -0800 Subject: [PATCH 06/11] Add configuration support for peer_private. --- rippled-example.cfg | 8 +++++++- src/cpp/ripple/Config.cpp | 6 ++++++ src/cpp/ripple/Config.h | 3 ++- 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/rippled-example.cfg b/rippled-example.cfg index a57fa3a8c..0bbd0f5dd 100644 --- a/rippled-example.cfg +++ b/rippled-example.cfg @@ -76,6 +76,11 @@ # [peer_port]: # Port to bind to allow external connections from peers. # +# [peer_private]: +# 0 or 1. +# 0: allow peers to broadcast your address. [default] +# 1: request peers not broadcast your address. +# # [rpc_ip]: # IP address or domain to bind to allow insecure RPC connections. # Defaults to not allow RPC connections. @@ -84,7 +89,8 @@ # 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] +# 0 or 1. +# 0: only allows RPC connections from 127.0.0.1. [default] # # [websocket_ip]: # IP address or domain to bind to allow client connections. diff --git a/src/cpp/ripple/Config.cpp b/src/cpp/ripple/Config.cpp index 68f2e3192..18c60c235 100644 --- a/src/cpp/ripple/Config.cpp +++ b/src/cpp/ripple/Config.cpp @@ -20,6 +20,7 @@ #define SECTION_PEER_CONNECT_LOW_WATER "peer_connect_low_water" #define SECTION_PEER_IP "peer_ip" #define SECTION_PEER_PORT "peer_port" +#define SECTION_PEER_PRIVATE "peer_private" #define SECTION_PEER_SCAN_INTERVAL_MIN "peer_scan_interval_min" #define SECTION_PEER_SSL_CIPHER_LIST "peer_ssl_cipher_list" #define SECTION_PEER_START_MAX "peer_start_max" @@ -143,6 +144,8 @@ void Config::setup(const std::string& strConf) PEER_START_MAX = DEFAULT_PEER_START_MAX; PEER_CONNECT_LOW_WATER = DEFAULT_PEER_CONNECT_LOW_WATER; + PEER_PRIVATE = false; + TRANSACTION_FEE_BASE = 1000; NETWORK_QUORUM = 0; // Don't need to see other nodes @@ -222,6 +225,9 @@ void Config::load() if (sectionSingleB(secConfig, SECTION_PEER_PORT, strTemp)) PEER_PORT = boost::lexical_cast(strTemp); + if (sectionSingleB(secConfig, SECTION_PEER_PRIVATE, strTemp)) + PEER_PRIVATE = boost::lexical_cast(strTemp); + (void) sectionSingleB(secConfig, SECTION_RPC_IP, RPC_IP); if (sectionSingleB(secConfig, SECTION_RPC_PORT, strTemp)) diff --git a/src/cpp/ripple/Config.h b/src/cpp/ripple/Config.h index 199b4292e..2caf47abf 100644 --- a/src/cpp/ripple/Config.h +++ b/src/cpp/ripple/Config.h @@ -66,7 +66,7 @@ public: int LEDGER_SECONDS; int LEDGER_PROPOSAL_DELAY_SECONDS; int LEDGER_AVALANCHE_SECONDS; - bool LEDGER_CREATOR; // should be false unless we are starting a new ledger + bool LEDGER_CREATOR; // Should be false unless we are starting a new ledger. bool RUN_STANDALONE; // Note: The following parameters do not relate to the UNL or trust at all @@ -81,6 +81,7 @@ public: int PEER_SCAN_INTERVAL_MIN; int PEER_START_MAX; unsigned int PEER_CONNECT_LOW_WATER; + bool PEER_PRIVATE; // True to ask peers not to relay current IP. // Websocket networking parameters std::string WEBSOCKET_PUBLIC_IP; // XXX Going away. Merge with the inbound peer connction. From ad4725ae744a833a8f4de53aacca0ef592d2faeb Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Tue, 20 Nov 2012 14:48:53 -0800 Subject: [PATCH 07/11] Add private peers. --- src/cpp/ripple/ConnectionPool.cpp | 1 + src/cpp/ripple/Peer.cpp | 22 +++++++++++++++++++--- src/cpp/ripple/Peer.h | 1 + src/cpp/ripple/ripple.proto | 2 +- 4 files changed, 22 insertions(+), 4 deletions(-) diff --git a/src/cpp/ripple/ConnectionPool.cpp b/src/cpp/ripple/ConnectionPool.cpp index 121eea8e6..85bc05ea5 100644 --- a/src/cpp/ripple/ConnectionPool.cpp +++ b/src/cpp/ripple/ConnectionPool.cpp @@ -300,6 +300,7 @@ void ConnectionPool::connectTo(const std::string& strIp, int iPort) { if (theConfig.RUN_STANDALONE) return; + { Database* db = theApp->getWalletDB()->getDB(); ScopedLock sl(theApp->getWalletDB()->getDBLock()); diff --git a/src/cpp/ripple/Peer.cpp b/src/cpp/ripple/Peer.cpp index 76e396b3e..c42108e2e 100644 --- a/src/cpp/ripple/Peer.cpp +++ b/src/cpp/ripple/Peer.cpp @@ -430,24 +430,29 @@ void Peer::processReadBuffer() case ripple::mtCONTACT: { ripple::TMContact msg; + if (msg.ParseFromArray(&mReadbuf[HEADER_SIZE], mReadbuf.size() - HEADER_SIZE)) recvContact(msg); else cLog(lsWARNING) << "parse error: " << type; } break; + case ripple::mtGET_PEERS: { ripple::TMGetPeers msg; + if (msg.ParseFromArray(&mReadbuf[HEADER_SIZE], mReadbuf.size() - HEADER_SIZE)) recvGetPeers(msg); else cLog(lsWARNING) << "parse error: " << type; } break; + case ripple::mtPEERS: { ripple::TMPeers msg; + if (msg.ParseFromArray(&mReadbuf[HEADER_SIZE], mReadbuf.size() - HEADER_SIZE)) recvPeers(msg); else @@ -666,7 +671,17 @@ void Peer::recvHello(ripple::TMHello& packet) std::string strIP = getSocket().remote_endpoint().address().to_string(); int iPort = packet.ipv4port(); - theApp->getConnectionPool().savePeer(strIP, iPort, UniqueNodeList::vsInbound); + if (mHello.nodeprivate()) + { + cLog(lsINFO) << boost::str(boost::format("Recv(Hello): Private connection: %s %s") % strIP % iPort); + } + else + { + // Don't save IP address if the node wants privacy. + // Note: We don't go so far as to delete it. If a node which has previously announced itself now wants + // privacy, it should at least change its port. + theApp->getConnectionPool().savePeer(strIP, iPort, UniqueNodeList::vsInbound); + } } // Consider us connected. No longer accepting mtHELLO. @@ -994,7 +1009,7 @@ void Peer::recvGetContacts(ripple::TMGetContacts& packet) { } -// return a list of your favorite people +// Return a list of your favorite people // TODO: filter out all the LAN peers // TODO: filter out the peer you are talking to void Peer::recvGetPeers(ripple::TMGetPeers& packet) @@ -1510,6 +1525,7 @@ void Peer::sendHello() h.set_nodepublic(theApp->getWallet().getNodePublic().humanNodePublic()); h.set_nodeproof(&vchSig[0], vchSig.size()); h.set_ipv4port(theConfig.PEER_PORT); + h.set_nodeprivate(theConfig.PEER_PRIVATE); Ledger::pointer closedLedger = theApp->getMasterLedger().getClosedLedger(); if (closedLedger && closedLedger->isClosed()) @@ -1526,7 +1542,7 @@ void Peer::sendHello() void Peer::sendGetPeers() { - // get other peers this guy knows about + // Ask peer for known other peers. ripple::TMGetPeers getPeers; getPeers.set_doweneedthis(1); diff --git a/src/cpp/ripple/Peer.h b/src/cpp/ripple/Peer.h index 3865e8aa3..f3c29c0f2 100644 --- a/src/cpp/ripple/Peer.h +++ b/src/cpp/ripple/Peer.h @@ -49,6 +49,7 @@ private: ipPort mIpPortConnect; uint256 mCookieHash; uint64 mPeerId; + bool mPrivate; // Keep peer IP private. uint256 mClosedLedgerHash, mPreviousLedgerHash; std::list mRecentLedgers; diff --git a/src/cpp/ripple/ripple.proto b/src/cpp/ripple/ripple.proto index 6d2292436..5ffbb657d 100644 --- a/src/cpp/ripple/ripple.proto +++ b/src/cpp/ripple/ripple.proto @@ -34,7 +34,6 @@ enum MessageType { // Sent on connect - message TMHello { required uint32 protoVersion = 1; required uint32 protoVersionMin = 2; @@ -46,6 +45,7 @@ message TMHello { optional uint32 ledgerIndex = 8; optional bytes ledgerClosed = 9; // our last closed ledger optional bytes ledgerPrevious = 10; // the ledger before the last closed ledger + optional bool nodePrivate = 11; // Request to not forward IP. } From 8e520e881600a843ee4b529dd37f811738471c30 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Tue, 20 Nov 2012 15:20:43 -0800 Subject: [PATCH 08/11] Locking fixes. --- src/cpp/ripple/WSConnection.cpp | 15 +++++++++------ src/cpp/ripple/WSHandler.h | 9 ++++++++- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/src/cpp/ripple/WSConnection.cpp b/src/cpp/ripple/WSConnection.cpp index ae6a70ee8..8030cdc67 100644 --- a/src/cpp/ripple/WSConnection.cpp +++ b/src/cpp/ripple/WSConnection.cpp @@ -49,12 +49,15 @@ Json::Value WSConnection::invokeCommand(Json::Value& jvRequest) Json::Value jvResult(Json::objectValue); // Regular RPC command - jvResult["result"] = mRPCHandler.doCommand( - jvRequest["command"].asString(), - jvRequest.isMember("params") - ? jvRequest["params"] - : jvRequest, - mHandler->getPublic() ? RPCHandler::GUEST : RPCHandler::ADMIN); + { + boost::recursive_mutex::scoped_lock sl(theApp->getMasterLock()); + jvResult["result"] = mRPCHandler.doCommand( + jvRequest["command"].asString(), + jvRequest.isMember("params") + ? jvRequest["params"] + : jvRequest, + mHandler->getPublic() ? RPCHandler::GUEST : RPCHandler::ADMIN); + } // Currently we will simply unwrap errors returned by the RPC // API, in the future maybe we can make the responses diff --git a/src/cpp/ripple/WSHandler.h b/src/cpp/ripple/WSHandler.h index 306647c5c..9f4b23d5e 100644 --- a/src/cpp/ripple/WSHandler.h +++ b/src/cpp/ripple/WSHandler.h @@ -116,7 +116,14 @@ public: } else { - send(cpClient, mMap[cpClient]->invokeCommand(jvRequest)); + boost::shared_ptr conn; + { + boost::mutex::scoped_lock sl(mMapLock); + conn = mMap[cpClient]; + } + if (!conn) + return; + send(cpClient, conn->invokeCommand(jvRequest)); } } From 9755563e186423bb356b3e5029a61052150da38e Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Tue, 20 Nov 2012 18:52:42 -0800 Subject: [PATCH 09/11] Cosmetic changes for path finding. --- src/cpp/ripple/Pathfinder.cpp | 183 ++++++++++++++++++---------------- src/cpp/ripple/RPCHandler.cpp | 101 +++++++++++-------- src/cpp/ripple/RPCHandler.h | 2 + 3 files changed, 160 insertions(+), 126 deletions(-) diff --git a/src/cpp/ripple/Pathfinder.cpp b/src/cpp/ripple/Pathfinder.cpp index 318d76371..4fd581157 100644 --- a/src/cpp/ripple/Pathfinder.cpp +++ b/src/cpp/ripple/Pathfinder.cpp @@ -36,27 +36,24 @@ Test XRP to USD Test USD to EUR */ - // we sort the options by: // cost of path // length of path // width of path // correct currency at the end - - bool sortPathOptions(PathOption::pointer first, PathOption::pointer second) { - if(first->mTotalCostmTotalCost) return(true); - if(first->mTotalCost>second->mTotalCost) return(false); + if (first->mTotalCostmTotalCost) return(true); + if (first->mTotalCost>second->mTotalCost) return(false); - if(first->mCorrectCurrency && !second->mCorrectCurrency) return(true); - if(!first->mCorrectCurrency && second->mCorrectCurrency) return(false); + if (first->mCorrectCurrency && !second->mCorrectCurrency) return(true); + if (!first->mCorrectCurrency && second->mCorrectCurrency) return(false); - if(first->mPath.getElementCount()mPath.getElementCount()) return(true); - if(first->mPath.getElementCount()>second->mPath.getElementCount()) return(false); + if (first->mPath.getElementCount()mPath.getElementCount()) return(true); + if (first->mPath.getElementCount()>second->mPath.getElementCount()) return(false); - if(first->mMinWidthmMinWidth) return true; + if (first->mMinWidthmMinWidth) return true; return false; } @@ -76,98 +73,115 @@ PathOption::PathOption(PathOption::pointer other) } -Pathfinder::Pathfinder(RippleAddress& srcAccountID, RippleAddress& dstAccountID, uint160& srcCurrencyID, STAmount dstAmount) : +Pathfinder::Pathfinder(RippleAddress& srcAccountID, RippleAddress& dstAccountID, uint160& srcCurrencyID, STAmount dstAmount) : mSrcAccountID(srcAccountID.getAccountID()), mDstAccountID(dstAccountID.getAccountID()), mDstAmount(dstAmount), mSrcCurrencyID(srcCurrencyID), mOrderBook(theApp->getMasterLedger().getCurrentLedger()) { mLedger=theApp->getMasterLedger().getCurrentLedger(); } +// Returns a single path, if possible. +// --> maxSearchSteps: unused +// --> maxPay: unused bool Pathfinder::findPaths(int maxSearchSteps, int maxPay, STPathSet& retPathSet) { - if(mLedger) { - std::queue pqueue; - STPathElement ele(mSrcAccountID, - mSrcCurrencyID, - uint160()); - STPath path; - path.addElement(ele); - pqueue.push(path); - while(pqueue.size()) { + if (mLedger) { + std::queue pqueue; + STPathElement ele(mSrcAccountID, + mSrcCurrencyID, + uint160()); + STPath path; - STPath path = pqueue.front(); - pqueue.pop(); - // get the first path from the queue + path.addElement(ele); // Add the source. - ele = path.mPath.back(); - // get the last node from the path + pqueue.push(path); - if (ele.mAccountID == mDstAccountID) { - path.mPath.erase(path.mPath.begin()); - path.mPath.erase(path.mPath.begin() + path.mPath.size()-1); - if (path.mPath.size() == 0) { - continue; - } - retPathSet.addPath(path); - return true; - } - // found the destination + while (pqueue.size()) { + STPath path = pqueue.front(); - if (!ele.mCurrencyID) { - BOOST_FOREACH(OrderBook::pointer book,mOrderBook.getXRPInBooks()) - { - //if (!path.hasSeen(line->getAccountIDPeer().getAccountID())) - { + pqueue.pop(); // Pop the first path from the queue. - STPath new_path(path); - STPathElement new_ele(uint160(), book->getCurrencyOut(), book->getIssuerOut()); - new_path.mPath.push_back(new_ele); - new_path.mCurrencyID = book->getCurrencyOut(); - new_path.mCurrentAccount = book->getCurrencyOut(); + ele = path.mPath.back(); // Get the last node from the path. - pqueue.push(new_path); + // Determine if path is solved. + if (ele.mAccountID == mDstAccountID) { + // Found a path to the destination. - } - } + if (2 == path.mPath.size()) { + // Empty path is default. Drop it. + continue; + } - } else { - RippleLines rippleLines(ele.mAccountID); - BOOST_FOREACH(RippleState::pointer line,rippleLines.getLines()) - { - if (!path.hasSeen(line->getAccountIDPeer().getAccountID())) - { - STPath new_path(path); - STPathElement new_ele(line->getAccountIDPeer().getAccountID(), - ele.mCurrencyID, - uint160()); - - new_path.mPath.push_back(new_ele); - pqueue.push(new_path); - } - } // BOOST_FOREACHE + // Remove implied first and last nodes. + path.mPath.erase(path.mPath.begin()); + path.mPath.erase(path.mPath.begin() + path.mPath.size()-1); - // every offer that wants the source currency - std::vector books; - mOrderBook.getBooks(path.mCurrentAccount, path.mCurrencyID, books); + // Return the path. + retPathSet.addPath(path); - BOOST_FOREACH(OrderBook::pointer book,books) - { - STPath new_path(path); - STPathElement new_ele(uint160(), book->getCurrencyOut(), book->getIssuerOut()); + return true; + } - new_path.mPath.push_back(new_ele); - new_path.mCurrentAccount=book->getIssuerOut(); - new_path.mCurrencyID=book->getCurrencyOut(); + if (!ele.mCurrencyID) { + // Last element is for XRP continue with qualifying books. - pqueue.push(new_path); + BOOST_FOREACH(OrderBook::pointer book, mOrderBook.getXRPInBooks()) + { + //if (!path.hasSeen(line->getAccountIDPeer().getAccountID())) + { + STPath new_path(path); + STPathElement new_ele(uint160(), book->getCurrencyOut(), book->getIssuerOut()); - } + new_path.mPath.push_back(new_ele); + new_path.mCurrencyID = book->getCurrencyOut(); + new_path.mCurrentAccount = book->getCurrencyOut(); - } // else - // enumerate all adjacent nodes, construct a new path and push it into the queue - } // While - } // if there is a ledger + pqueue.push(new_path); + } + } - return false; + } else { + // Last element is for non-XRP continue by adding ripple lines and order books. + + // Create new paths for each outbound account not already in the path. + RippleLines rippleLines(ele.mAccountID); + + BOOST_FOREACH(RippleState::pointer line, rippleLines.getLines()) + { + if (!path.hasSeen(line->getAccountIDPeer().getAccountID())) + { + STPath new_path(path); + STPathElement new_ele(line->getAccountIDPeer().getAccountID(), + ele.mCurrencyID, + uint160()); + + new_path.mPath.push_back(new_ele); + pqueue.push(new_path); + } + } + + // Every book that wants the source currency. + std::vector books; + + mOrderBook.getBooks(path.mCurrentAccount, path.mCurrencyID, books); + + BOOST_FOREACH(OrderBook::pointer book,books) + { + STPath new_path(path); + STPathElement new_ele(uint160(), book->getCurrencyOut(), book->getIssuerOut()); + + new_path.mPath.push_back(new_ele); + new_path.mCurrentAccount=book->getIssuerOut(); + new_path.mCurrencyID=book->getCurrencyOut(); + + pqueue.push(new_path); + } + } + + // enumerate all adjacent nodes, construct a new path and push it into the queue + } // While + } // if there is a ledger + + return false; } bool Pathfinder::checkComplete(STPathSet& retPathSet) @@ -196,9 +210,9 @@ bool Pathfinder::checkComplete(STPathSet& retPathSet) void Pathfinder::addOptions(PathOption::pointer tail) { - if(!tail->mCurrencyID) + if (!tail->mCurrencyID) { // source XRP - BOOST_FOREACH(OrderBook::pointer book,mOrderBook.getXRPInBooks()) + BOOST_FOREACH(OrderBook::pointer book, mOrderBook.getXRPInBooks()) { PathOption::pointer pathOption(new PathOption(tail)); @@ -209,13 +223,14 @@ void Pathfinder::addOptions(PathOption::pointer tail) pathOption->mCurrencyID=book->getCurrencyOut(); addPathOption(pathOption); } - }else + } + else { // ripple RippleLines rippleLines(tail->mCurrentAccount); BOOST_FOREACH(RippleState::pointer line,rippleLines.getLines()) { // TODO: make sure we can move in the correct direction - STAmount balance=line->getBalance(); + STAmount balance=line->getBalance(); if(balance.getCurrency()==tail->mCurrencyID) { // we have a ripple line from the tail to somewhere else PathOption::pointer pathOption(new PathOption(tail)); diff --git a/src/cpp/ripple/RPCHandler.cpp b/src/cpp/ripple/RPCHandler.cpp index 2273f2c18..001fe40a5 100644 --- a/src/cpp/ripple/RPCHandler.cpp +++ b/src/cpp/ripple/RPCHandler.cpp @@ -526,11 +526,19 @@ Json::Value RPCHandler::doOwnerInfo(const Json::Value& params) } +Json::Value RPCHandler::doPathFind(const Json::Value& params) +{ + Json::Value ret(Json::objectValue); + + return ret; +} + Json::Value RPCHandler::doPeers(const Json::Value& params) { - // peers Json::Value obj(Json::objectValue); + obj["peers"]=theApp->getConnectionPool().getPeersJson(); + return obj; } @@ -759,20 +767,21 @@ Json::Value RPCHandler::handleJSONSubmit(const Json::Value& jvRequest) return rpcError(rpcDST_ACT_MALFORMED); } - if(!txJSON.isMember("Fee")) + if (!txJSON.isMember("Fee")) { - if(mNetOps->getAccountState(uint256(0), dstAccountID)) + if (mNetOps->getAccountState(uint256(0), dstAccountID)) txJSON["Fee"]=(int)theConfig.FEE_DEFAULT; else txJSON["Fee"]=(int)theConfig.FEE_ACCOUNT_CREATE; } - if(!txJSON.isMember("Paths") && jvRequest.isMember("build_path") ) + if (!txJSON.isMember("Paths") && jvRequest.isMember("build_path")) { - if(txJSON["Amount"].isObject() || txJSON.isMember("SendMax") ) + if (txJSON["Amount"].isObject() || txJSON.isMember("SendMax")) { // we need a ripple path STPathSet spsPaths; uint160 srcCurrencyID; - if(txJSON.isMember("SendMax") && txJSON["SendMax"].isMember("currency")) + + if (txJSON.isMember("SendMax") && txJSON["SendMax"].isMember("currency")) { STAmount::currencyFromString(srcCurrencyID, txJSON["SendMax"]["currency"].asString()); } @@ -782,7 +791,8 @@ Json::Value RPCHandler::handleJSONSubmit(const Json::Value& jvRequest) } STAmount dstAmount; - if(txJSON["Amount"].isObject()) + + if (txJSON["Amount"].isObject()) { std::string issuerStr; if( txJSON["Amount"].isMember("issuer")) issuerStr=txJSON["Amount"]["issuer"].asString(); @@ -791,14 +801,17 @@ Json::Value RPCHandler::handleJSONSubmit(const Json::Value& jvRequest) { return rpcError(rpcDST_AMT_MALFORMED); } - }else if (!dstAmount.setFullValue(txJSON["Amount"].asString())) + } + else if (!dstAmount.setFullValue(txJSON["Amount"].asString())) { return rpcError(rpcDST_AMT_MALFORMED); } Pathfinder pf(srcAddress, dstAccountID, srcCurrencyID, dstAmount); + pf.findPaths(5, 1, spsPaths); - if(!spsPaths.isEmpty()) + + if (!spsPaths.isEmpty()) { txJSON["Paths"]=spsPaths.getJson(0); if(txJSON.isMember("Flags")) txJSON["Flags"]=txJSON["Flags"].asUInt() | 2; @@ -806,16 +819,18 @@ Json::Value RPCHandler::handleJSONSubmit(const Json::Value& jvRequest) } } } - - }else if( txJSON["type"]=="OfferCreate" ) + } + else if( txJSON["type"]=="OfferCreate" ) { txJSON["TransactionType"]=7; if(!txJSON.isMember("Fee")) txJSON["Fee"]=(int)theConfig.FEE_DEFAULT; - }else if( txJSON["type"]=="TrustSet") + } + else if( txJSON["type"]=="TrustSet") { txJSON["TransactionType"]=20; if(!txJSON.isMember("Fee")) txJSON["Fee"]=(int)theConfig.FEE_DEFAULT; - }else if( txJSON["type"]=="OfferCancel") + } + else if( txJSON["type"]=="OfferCancel") { txJSON["TransactionType"]=8; if(!txJSON.isMember("Fee")) txJSON["Fee"]=(int)theConfig.FEE_DEFAULT; @@ -1332,55 +1347,57 @@ Json::Value RPCHandler::doCommand(const std::string& command, Json::Value& param unsigned int iOptions; } commandsA[] = { // Request-response methods - { "accept_ledger", &RPCHandler::doAcceptLedger, 0, 0, true }, + { "accept_ledger", &RPCHandler::doAcceptLedger, 0, 0, true, false, optNone }, { "account_info", &RPCHandler::doAccountInfo, 1, 2, false, false, optCurrent }, { "account_tx", &RPCHandler::doAccountTransactions, 2, 3, false, false, optNetwork }, - { "connect", &RPCHandler::doConnect, 1, 2, true }, - { "data_delete", &RPCHandler::doDataDelete, 1, 1, true }, - { "data_fetch", &RPCHandler::doDataFetch, 1, 1, true }, - { "data_store", &RPCHandler::doDataStore, 2, 2, true }, - { "get_counts", &RPCHandler::doGetCounts, 0, 1, true }, + { "connect", &RPCHandler::doConnect, 1, 2, true, false, optNone }, + { "data_delete", &RPCHandler::doDataDelete, 1, 1, true, false, optNone }, + { "data_fetch", &RPCHandler::doDataFetch, 1, 1, true, false, optNone }, + { "data_store", &RPCHandler::doDataStore, 2, 2, true, false, optNone }, + { "get_counts", &RPCHandler::doGetCounts, 0, 1, true, false, optNone }, { "ledger", &RPCHandler::doLedger, 0, 2, false, false, optNetwork }, { "ledger_accept", &RPCHandler::doLedgerAccept, 0, 0, true, false, optCurrent }, { "ledger_closed", &RPCHandler::doLedgerClosed, 0, 0, false, false, optClosed }, { "ledger_current", &RPCHandler::doLedgerCurrent, 0, 0, false, false, optCurrent }, - { "ledger_entry", &RPCHandler::doLedgerEntry, -1, -1, false, false, optCurrent }, - { "ledger_header", &RPCHandler::doLedgerHeader, -1, -1, false, false, optCurrent }, - { "log_level", &RPCHandler::doLogLevel, 0, 2, true }, - { "logrotate", &RPCHandler::doLogRotate, 0, 0, true }, + { "ledger_entry", &RPCHandler::doLedgerEntry, -1, -1, false, false, optCurrent }, + { "ledger_header", &RPCHandler::doLedgerHeader, -1, -1, false, false, optCurrent }, + { "log_level", &RPCHandler::doLogLevel, 0, 2, true, false, optNone }, + { "logrotate", &RPCHandler::doLogRotate, 0, 0, true, false, optNone }, { "nickname_info", &RPCHandler::doNicknameInfo, 1, 1, false, false, optCurrent }, { "owner_info", &RPCHandler::doOwnerInfo, 1, 2, false, false, optCurrent }, - { "peers", &RPCHandler::doPeers, 0, 0, true }, + { "path_find", &RPCHandler::doPathFind, -1, -1, false, false, optCurrent }, + { "peers", &RPCHandler::doPeers, 0, 0, true, false, optNone }, { "profile", &RPCHandler::doProfile, 1, 9, false, false, optCurrent }, { "ripple_lines_get", &RPCHandler::doRippleLinesGet, 1, 2, false, false, optCurrent }, { "submit", &RPCHandler::doSubmit, 2, 2, false, false, optCurrent }, { "submit_json", &RPCHandler::doSubmitJson, -1, -1, false, false, optCurrent }, - { "server_info", &RPCHandler::doServerInfo, 0, 0, true }, - { "stop", &RPCHandler::doStop, 0, 0, true }, + { "server_info", &RPCHandler::doServerInfo, 0, 0, true, false, optNone }, + { "stop", &RPCHandler::doStop, 0, 0, true, false, optNone }, { "transaction_entry", &RPCHandler::doTransactionEntry, -1, -1, false, false, optCurrent }, - { "tx", &RPCHandler::doTx, 1, 1, true }, - { "tx_history", &RPCHandler::doTxHistory, 1, 1, false, }, + { "tx", &RPCHandler::doTx, 1, 1, true, false, optNone }, + { "tx_history", &RPCHandler::doTxHistory, 1, 1, false, false, optNone }, - { "unl_add", &RPCHandler::doUnlAdd, 1, 2, true }, - { "unl_delete", &RPCHandler::doUnlDelete, 1, 1, true }, - { "unl_list", &RPCHandler::doUnlList, 0, 0, true }, - { "unl_load", &RPCHandler::doUnlLoad, 0, 0, true }, - { "unl_network", &RPCHandler::doUnlNetwork, 0, 0, true }, - { "unl_reset", &RPCHandler::doUnlReset, 0, 0, true }, - { "unl_score", &RPCHandler::doUnlScore, 0, 0, true }, + { "unl_add", &RPCHandler::doUnlAdd, 1, 2, true, false, optNone }, + { "unl_delete", &RPCHandler::doUnlDelete, 1, 1, true, false, optNone }, + { "unl_list", &RPCHandler::doUnlList, 0, 0, true, false, optNone }, + { "unl_load", &RPCHandler::doUnlLoad, 0, 0, true, false, optNone }, + { "unl_network", &RPCHandler::doUnlNetwork, 0, 0, true, false, optNone }, + { "unl_reset", &RPCHandler::doUnlReset, 0, 0, true, false, optNone }, + { "unl_score", &RPCHandler::doUnlScore, 0, 0, true, false, optNone }, - { "validation_create", &RPCHandler::doValidationCreate, 0, 1, false }, - { "validation_seed", &RPCHandler::doValidationSeed, 0, 1, false }, + { "validation_create", &RPCHandler::doValidationCreate, 0, 1, false, false, optNone }, + { "validation_seed", &RPCHandler::doValidationSeed, 0, 1, false, false, optNone }, { "wallet_accounts", &RPCHandler::doWalletAccounts, 1, 1, false, false, optCurrent }, - { "wallet_propose", &RPCHandler::doWalletPropose, 0, 1, false, }, - { "wallet_seed", &RPCHandler::doWalletSeed, 0, 1, false, }, + { "wallet_propose", &RPCHandler::doWalletPropose, 0, 1, false, false, optNone }, + { "wallet_seed", &RPCHandler::doWalletSeed, 0, 1, false, false, optNone }, - { "login", &RPCHandler::doLogin, 2, 2, true }, + { "login", &RPCHandler::doLogin, 2, 2, true, false, optNone }, // Evented methods - { "subscribe", &RPCHandler::doSubscribe, -1, -1, false, true }, - { "unsubscribe", &RPCHandler::doUnsubscribe, -1, -1, false, true }, }; + { "subscribe", &RPCHandler::doSubscribe, -1, -1, false, true, optNone }, + { "unsubscribe", &RPCHandler::doUnsubscribe, -1, -1, false, true, optNone }, + }; int i = NUMBER(commandsA); diff --git a/src/cpp/ripple/RPCHandler.h b/src/cpp/ripple/RPCHandler.h index 0b742c8dd..e2f1a25b7 100644 --- a/src/cpp/ripple/RPCHandler.h +++ b/src/cpp/ripple/RPCHandler.h @@ -12,6 +12,7 @@ class RPCHandler typedef Json::Value (RPCHandler::*doFuncPtr)(const Json::Value ¶ms); enum { + optNone = 0, optNetwork = 1, // Need network optCurrent = 2+optNetwork, // Need current ledger optClosed = 4+optNetwork, // Need closed ledger @@ -50,6 +51,7 @@ class RPCHandler Json::Value doOwnerInfo(const Json::Value& params); Json::Value doProfile(const Json::Value& params); + Json::Value doPathFind(const Json::Value& params); Json::Value doPeers(const Json::Value& params); Json::Value doRippleLinesGet(const Json::Value ¶ms); From 89d54999c9c1b28d89fc824e34369c9acd31b101 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Wed, 21 Nov 2012 09:28:09 -0800 Subject: [PATCH 10/11] Rework the way the results of ledger and TX map acquisition is passed up and down the call chain so that the peer logic will know how helpful peers are being, not just whether they're sending invalid data. --- src/cpp/ripple/LedgerAcquire.cpp | 67 ++++++++++++++++-------------- src/cpp/ripple/LedgerAcquire.h | 12 +++--- src/cpp/ripple/LedgerConsensus.cpp | 22 +++++----- src/cpp/ripple/LedgerConsensus.h | 5 ++- src/cpp/ripple/NetworkOPs.cpp | 4 +- src/cpp/ripple/NetworkOPs.h | 2 +- src/cpp/ripple/Peer.cpp | 6 ++- src/cpp/ripple/Peer.h | 6 +++ src/cpp/ripple/ProofOfWork.cpp | 20 ++++++++- src/cpp/ripple/SHAMap.h | 44 ++++++++++++++++++-- src/cpp/ripple/SHAMapSync.cpp | 51 ++++++++++++----------- 11 files changed, 155 insertions(+), 84 deletions(-) diff --git a/src/cpp/ripple/LedgerAcquire.cpp b/src/cpp/ripple/LedgerAcquire.cpp index 0d979f61d..c3387cf5f 100644 --- a/src/cpp/ripple/LedgerAcquire.cpp +++ b/src/cpp/ripple/LedgerAcquire.cpp @@ -396,7 +396,7 @@ bool LedgerAcquire::takeBase(const std::string& data) } bool LedgerAcquire::takeTxNode(const std::list& nodeIDs, - const std::list< std::vector >& data) + const std::list< std::vector >& data, SMAddNode& san) { if (!mHaveBase) return false; std::list::const_iterator nodeIDit = nodeIDs.begin(); @@ -406,11 +406,15 @@ bool LedgerAcquire::takeTxNode(const std::list& nodeIDs, { if (nodeIDit->isRoot()) { - if (!mLedger->peekTransactionMap()->addRootNode(mLedger->getTransHash(), *nodeDatait, snfWIRE, &tFilter)) + if (!san.combine(mLedger->peekTransactionMap()->addRootNode(mLedger->getTransHash(), *nodeDatait, + snfWIRE, &tFilter))) + return false; + } + else + { + if (!san.combine(mLedger->peekTransactionMap()->addKnownNode(*nodeIDit, *nodeDatait, &tFilter))) return false; } - else if (!mLedger->peekTransactionMap()->addKnownNode(*nodeIDit, *nodeDatait, &tFilter)) - return false; ++nodeIDit; ++nodeDatait; } @@ -428,7 +432,7 @@ bool LedgerAcquire::takeTxNode(const std::list& nodeIDs, } bool LedgerAcquire::takeAsNode(const std::list& nodeIDs, - const std::list< std::vector >& data) + const std::list< std::vector >& data, SMAddNode& san) { cLog(lsTRACE) << "got ASdata (" << nodeIDs.size() <<") acquiring ledger " << mHash; tLog(nodeIDs.size() == 1, lsTRACE) << "got AS node: " << nodeIDs.front(); @@ -446,14 +450,14 @@ bool LedgerAcquire::takeAsNode(const std::list& nodeIDs, { if (nodeIDit->isRoot()) { - if (!mLedger->peekAccountStateMap()->addRootNode(mLedger->getAccountHash(), - *nodeDatait, snfWIRE, &tFilter)) + if (!san.combine(mLedger->peekAccountStateMap()->addRootNode(mLedger->getAccountHash(), + *nodeDatait, snfWIRE, &tFilter))) { cLog(lsWARNING) << "Bad ledger base"; return false; } } - else if (!mLedger->peekAccountStateMap()->addKnownNode(*nodeIDit, *nodeDatait, &tFilter)) + else if (!san.combine(mLedger->peekAccountStateMap()->addKnownNode(*nodeIDit, *nodeDatait, &tFilter))) { cLog(lsWARNING) << "Unable to add AS node"; return false; @@ -474,24 +478,22 @@ bool LedgerAcquire::takeAsNode(const std::list& nodeIDs, return true; } -bool LedgerAcquire::takeAsRootNode(const std::vector& data) +bool LedgerAcquire::takeAsRootNode(const std::vector& data, SMAddNode& san) { if (!mHaveBase) return false; AccountStateSF tFilter(mLedger->getHash(), mLedger->getLedgerSeq()); - if (!mLedger->peekAccountStateMap()->addRootNode(mLedger->getAccountHash(), data, snfWIRE, &tFilter)) - return false; - return true; + return san.combine( + mLedger->peekAccountStateMap()->addRootNode(mLedger->getAccountHash(), data, snfWIRE, &tFilter)); } -bool LedgerAcquire::takeTxRootNode(const std::vector& data) +bool LedgerAcquire::takeTxRootNode(const std::vector& data, SMAddNode& san) { if (!mHaveBase) return false; TransactionStateSF tFilter(mLedger->getHash(), mLedger->getLedgerSeq()); - if (!mLedger->peekTransactionMap()->addRootNode(mLedger->getTransHash(), data, snfWIRE, &tFilter)) - return false; - return true; + return san.combine( + mLedger->peekTransactionMap()->addRootNode(mLedger->getTransHash(), data, snfWIRE, &tFilter)); } LedgerAcquire::pointer LedgerAcquireMaster::findCreate(const uint256& hash) @@ -532,13 +534,13 @@ void LedgerAcquireMaster::dropLedger(const uint256& hash) mLedgers.erase(hash); } -bool LedgerAcquireMaster::gotLedgerData(ripple::TMLedgerData& packet, Peer::ref peer) +SMAddNode LedgerAcquireMaster::gotLedgerData(ripple::TMLedgerData& packet, Peer::ref peer) { uint256 hash; if (packet.ledgerhash().size() != 32) { std::cerr << "Acquire error" << std::endl; - return false; + return SMAddNode::invalid(); } memcpy(hash.begin(), packet.ledgerhash().data(), 32); cLog(lsTRACE) << "Got data (" << packet.nodes().size() << ") for acquiring ledger: " << hash; @@ -547,7 +549,7 @@ bool LedgerAcquireMaster::gotLedgerData(ripple::TMLedgerData& packet, Peer::ref if (!ledger) { cLog(lsINFO) << "Got data for ledger we're not acquiring"; - return false; + return SMAddNode(); } if (packet.type() == ripple::liBASE) @@ -555,23 +557,24 @@ bool LedgerAcquireMaster::gotLedgerData(ripple::TMLedgerData& packet, Peer::ref if (packet.nodes_size() < 1) { cLog(lsWARNING) << "Got empty base data"; - return false; + return SMAddNode::invalid(); } if (!ledger->takeBase(packet.nodes(0).nodedata())) { cLog(lsWARNING) << "Got invalid base data"; - return false; + return SMAddNode::invalid(); } - if ((packet.nodes().size() > 1) && !ledger->takeAsRootNode(strCopy(packet.nodes(1).nodedata()))) + SMAddNode san = SMAddNode::useful(); + if ((packet.nodes().size() > 1) && !ledger->takeAsRootNode(strCopy(packet.nodes(1).nodedata()), san)) { cLog(lsWARNING) << "Included ASbase invalid"; } - if ((packet.nodes().size() > 2) && !ledger->takeTxRootNode(strCopy(packet.nodes(2).nodedata()))) + if ((packet.nodes().size() > 2) && !ledger->takeTxRootNode(strCopy(packet.nodes(2).nodedata()), san)) { cLog(lsWARNING) << "Included TXbase invalid"; } ledger->trigger(peer, false); - return true; + return san; } if ((packet.type() == ripple::liTX_NODE) || (packet.type() == ripple::liAS_NODE)) @@ -581,8 +584,8 @@ bool LedgerAcquireMaster::gotLedgerData(ripple::TMLedgerData& packet, Peer::ref if (packet.nodes().size() <= 0) { - cLog(lsINFO) << "Got request for no nodes"; - return false; + cLog(lsINFO) << "Got response with no nodes"; + return SMAddNode::invalid(); } for (int i = 0; i < packet.nodes().size(); ++i) { @@ -590,24 +593,24 @@ bool LedgerAcquireMaster::gotLedgerData(ripple::TMLedgerData& packet, Peer::ref if (!node.has_nodeid() || !node.has_nodedata()) { cLog(lsWARNING) << "Got bad node"; - return false; + return SMAddNode::invalid(); } nodeIDs.push_back(SHAMapNode(node.nodeid().data(), node.nodeid().size())); nodeData.push_back(std::vector(node.nodedata().begin(), node.nodedata().end())); } - bool ret; + SMAddNode ret; if (packet.type() == ripple::liTX_NODE) - ret = ledger->takeTxNode(nodeIDs, nodeData); + ledger->takeTxNode(nodeIDs, nodeData, ret); else - ret = ledger->takeAsNode(nodeIDs, nodeData); - if (ret) + ledger->takeAsNode(nodeIDs, nodeData, ret); + if (!ret.isInvalid()) ledger->trigger(peer, false); return ret; } cLog(lsWARNING) << "Not sure what ledger data we got"; - return false; + return SMAddNode::invalid(); } // vim:ts=4 diff --git a/src/cpp/ripple/LedgerAcquire.h b/src/cpp/ripple/LedgerAcquire.h index eab3e47d8..2f9778c56 100644 --- a/src/cpp/ripple/LedgerAcquire.h +++ b/src/cpp/ripple/LedgerAcquire.h @@ -97,10 +97,12 @@ public: void addOnComplete(boost::function); bool takeBase(const std::string& data); - bool takeTxNode(const std::list& IDs, const std::list >& data); - bool takeTxRootNode(const std::vector& data); - bool takeAsNode(const std::list& IDs, const std::list >& data); - bool takeAsRootNode(const std::vector& data); + bool takeTxNode(const std::list& IDs, const std::list >& data, + SMAddNode&); + bool takeTxRootNode(const std::vector& data, SMAddNode&); + bool takeAsNode(const std::list& IDs, const std::list >& data, + SMAddNode&); + bool takeAsRootNode(const std::vector& data, SMAddNode&); void trigger(Peer::ref, bool timer); bool tryLocal(); void addPeers(); @@ -119,7 +121,7 @@ public: LedgerAcquire::pointer find(const uint256& hash); bool hasLedger(const uint256& ledgerHash); void dropLedger(const uint256& ledgerHash); - bool gotLedgerData(ripple::TMLedgerData& packet, Peer::ref); + SMAddNode gotLedgerData(ripple::TMLedgerData& packet, Peer::ref); }; #endif diff --git a/src/cpp/ripple/LedgerConsensus.cpp b/src/cpp/ripple/LedgerConsensus.cpp index 7cc01870d..27ac245ae 100644 --- a/src/cpp/ripple/LedgerConsensus.cpp +++ b/src/cpp/ripple/LedgerConsensus.cpp @@ -126,21 +126,23 @@ void TransactionAcquire::trigger(Peer::ref peer, bool timer) resetTimer(); } -bool TransactionAcquire::takeNodes(const std::list& nodeIDs, +SMAddNode TransactionAcquire::takeNodes(const std::list& nodeIDs, const std::list< std::vector >& data, Peer::ref peer) { if (mComplete) { cLog(lsTRACE) << "TX set complete"; - return true; + return SMAddNode(); } if (mFailed) { cLog(lsTRACE) << "TX set failed"; - return false; + return SMAddNode(); } try { + if (nodeIDs.empty()) + return SMAddNode::invalid(); std::list::const_iterator nodeIDit = nodeIDs.begin(); std::list< std::vector >::const_iterator nodeDatait = data.begin(); ConsensusTransSetSF sf; @@ -151,12 +153,12 @@ bool TransactionAcquire::takeNodes(const std::list& nodeIDs, if (mHaveRoot) { cLog(lsWARNING) << "Got root TXS node, already have it"; - return false; + return SMAddNode(); } if (!mMap->addRootNode(getHash(), *nodeDatait, snfWIRE, NULL)) { cLog(lsWARNING) << "TX acquire got bad root node"; - return false; + return SMAddNode::invalid(); } else mHaveRoot = true; @@ -164,19 +166,19 @@ bool TransactionAcquire::takeNodes(const std::list& nodeIDs, else if (!mMap->addKnownNode(*nodeIDit, *nodeDatait, &sf)) { cLog(lsWARNING) << "TX acquire got bad non-root node"; - return false; + return SMAddNode::invalid(); } ++nodeIDit; ++nodeDatait; } trigger(peer, false); progress(); - return true; + return SMAddNode::useful(); } catch (...) { cLog(lsERROR) << "Peer sends us junky transaction node data"; - return false; + return SMAddNode::invalid(); } } @@ -996,14 +998,14 @@ bool LedgerConsensus::peerHasSet(Peer::ref peer, const uint256& hashSet, ripple: return true; } -bool LedgerConsensus::peerGaveNodes(Peer::ref peer, const uint256& setHash, +SMAddNode LedgerConsensus::peerGaveNodes(Peer::ref peer, const uint256& setHash, const std::list& nodeIDs, const std::list< std::vector >& nodeData) { boost::unordered_map::iterator acq = mAcquiring.find(setHash); if (acq == mAcquiring.end()) { cLog(lsINFO) << "Got TX data for set not acquiring: " << setHash; - return false; + return SMAddNode(); } TransactionAcquire::pointer set = acq->second; // We must keep the set around during the function return set->takeNodes(nodeIDs, nodeData, peer); diff --git a/src/cpp/ripple/LedgerConsensus.h b/src/cpp/ripple/LedgerConsensus.h index 1db706996..accbb4df4 100644 --- a/src/cpp/ripple/LedgerConsensus.h +++ b/src/cpp/ripple/LedgerConsensus.h @@ -45,7 +45,8 @@ public: SHAMap::pointer getMap() { return mMap; } - bool takeNodes(const std::list& IDs, const std::list< std::vector >& data, Peer::ref); + SMAddNode takeNodes(const std::list& IDs, + const std::list< std::vector >& data, Peer::ref); }; class LCTransaction @@ -184,7 +185,7 @@ public: bool peerHasSet(Peer::ref peer, const uint256& set, ripple::TxSetStatus status); - bool peerGaveNodes(Peer::ref peer, const uint256& setHash, + SMAddNode peerGaveNodes(Peer::ref peer, const uint256& setHash, const std::list& nodeIDs, const std::list< std::vector >& nodeData); bool isOurPubKey(const RippleAddress &k) { return k == mValPublic; } diff --git a/src/cpp/ripple/NetworkOPs.cpp b/src/cpp/ripple/NetworkOPs.cpp index ed4847f9b..21933a88b 100644 --- a/src/cpp/ripple/NetworkOPs.cpp +++ b/src/cpp/ripple/NetworkOPs.cpp @@ -813,13 +813,13 @@ SHAMap::pointer NetworkOPs::getTXMap(const uint256& hash) return mConsensus->getTransactionTree(hash, false); } -bool NetworkOPs::gotTXData(const boost::shared_ptr& peer, const uint256& hash, +SMAddNode NetworkOPs::gotTXData(const boost::shared_ptr& peer, const uint256& hash, const std::list& nodeIDs, const std::list< std::vector >& nodeData) { if (!haveConsensusObject()) { cLog(lsWARNING) << "Got TX data with no consensus object"; - return false; + return SMAddNode(); } return mConsensus->peerGaveNodes(peer, hash, nodeIDs, nodeData); } diff --git a/src/cpp/ripple/NetworkOPs.h b/src/cpp/ripple/NetworkOPs.h index 778846a22..4826979e1 100644 --- a/src/cpp/ripple/NetworkOPs.h +++ b/src/cpp/ripple/NetworkOPs.h @@ -199,7 +199,7 @@ public: // ledger proposal/close functions void processTrustedProposal(LedgerProposal::pointer proposal, boost::shared_ptr set, RippleAddress nodePublic, uint256 checkLedger, bool sigGood); - bool gotTXData(const boost::shared_ptr& peer, const uint256& hash, + SMAddNode gotTXData(const boost::shared_ptr& peer, const uint256& hash, const std::list& nodeIDs, const std::list< std::vector >& nodeData); bool recvValidation(const SerializedValidation::pointer& val); SHAMap::pointer getTXMap(const uint256& hash); diff --git a/src/cpp/ripple/Peer.cpp b/src/cpp/ripple/Peer.cpp index c42108e2e..fcca1754d 100644 --- a/src/cpp/ripple/Peer.cpp +++ b/src/cpp/ripple/Peer.cpp @@ -1432,12 +1432,14 @@ void Peer::recvLedger(ripple::TMLedgerData& packet) nodeIDs.push_back(SHAMapNode(node.nodeid().data(), node.nodeid().size())); nodeData.push_back(std::vector(node.nodedata().begin(), node.nodedata().end())); } - if (!theApp->getOPs().gotTXData(shared_from_this(), hash, nodeIDs, nodeData)) + SMAddNode san = theApp->getOPs().gotTXData(shared_from_this(), hash, nodeIDs, nodeData); + if (san.isInvalid()) punishPeer(PP_UNWANTED_DATA); return; } - if (!theApp->getMasterLedgerAcquire().gotLedgerData(packet, shared_from_this())) + SMAddNode san = theApp->getMasterLedgerAcquire().gotLedgerData(packet, shared_from_this()); + if (san.isInvalid()) punishPeer(PP_UNWANTED_DATA); } diff --git a/src/cpp/ripple/Peer.h b/src/cpp/ripple/Peer.h index f3c29c0f2..c05aac0d2 100644 --- a/src/cpp/ripple/Peer.h +++ b/src/cpp/ripple/Peer.h @@ -22,6 +22,12 @@ enum PeerPunish PP_BAD_SIGNATURE = 4, // Object had bad signature }; +enum PeerReward +{ + PR_NEEDED_DATA = 1, + PR_NEW_TRANSACTION = 2, +}; + typedef std::pair ipPort; DEFINE_INSTANCE(Peer); diff --git a/src/cpp/ripple/ProofOfWork.cpp b/src/cpp/ripple/ProofOfWork.cpp index c550a9749..1e4ab5d9b 100644 --- a/src/cpp/ripple/ProofOfWork.cpp +++ b/src/cpp/ripple/ProofOfWork.cpp @@ -213,12 +213,28 @@ void ProofOfWorkGenerator::sweep() void ProofOfWorkGenerator::loadHigh() { - // WRITEME + time_t now = time(NULL); + + boost::mutex::scoped_lock sl(mLock); + if (mLastDifficultyChange == now) + return; + if (mPowEntry == 30) + return; + ++mPowEntry; + mLastDifficultyChange = now; } void ProofOfWorkGenerator::loadLow() { - // WRITEME + time_t now = time(NULL); + + boost::mutex::scoped_lock sl(mLock); + if (mLastDifficultyChange == now) + return; + if (mPowEntry == 0) + return; + --mPowEntry; + mLastDifficultyChange = now; } struct PowEntry diff --git a/src/cpp/ripple/SHAMap.h b/src/cpp/ripple/SHAMap.h index 7adc92bc2..c4d830262 100644 --- a/src/cpp/ripple/SHAMap.h +++ b/src/cpp/ripple/SHAMap.h @@ -281,6 +281,44 @@ public: extern std::ostream& operator<<(std::ostream&, const SHAMapMissingNode&); +class SMAddNode +{ // results of adding nodes +protected: + bool mInvalid, mUseful; + + SMAddNode(bool i, bool u) : mInvalid(i), mUseful(u) { ; } + +public: + SMAddNode() : mInvalid(false), mUseful(false) { ; } + + void setInvalid() { mInvalid = true; } + void setUseful() { mUseful = true; } + void reset() { mInvalid = false; mUseful = false; } + + bool isInvalid() const { return mInvalid; } + bool isUseful() const { return mUseful; } + + bool combine(const SMAddNode& n) + { + if (n.mInvalid) + { + mInvalid = true; + return false; + } + if (n.mUseful) + mUseful = true; + return true; + } + + operator bool() const { return !mInvalid; } + + static SMAddNode okay() { return SMAddNode(false, false); } + static SMAddNode useful() { return SMAddNode(false, true); } + static SMAddNode invalid() { return SMAddNode(true, false); } +}; + +extern bool SMANCombine(SMAddNode& existing, const SMAddNode& additional); + class SHAMap : public IS_INSTANCE(SHAMap) { public: @@ -374,11 +412,11 @@ public: bool getNodeFat(const SHAMapNode& node, std::vector& nodeIDs, std::list >& rawNode, bool fatRoot, bool fatLeaves); bool getRootNode(Serializer& s, SHANodeFormat format); - bool addRootNode(const uint256& hash, const std::vector& rootNode, SHANodeFormat format, + SMAddNode addRootNode(const uint256& hash, const std::vector& rootNode, SHANodeFormat format, SHAMapSyncFilter* filter); - bool addRootNode(const std::vector& rootNode, SHANodeFormat format, + SMAddNode addRootNode(const std::vector& rootNode, SHANodeFormat format, SHAMapSyncFilter* filter); - bool addKnownNode(const SHAMapNode& nodeID, const std::vector& rawNode, + SMAddNode addKnownNode(const SHAMapNode& nodeID, const std::vector& rawNode, SHAMapSyncFilter* filter); // status functions diff --git a/src/cpp/ripple/SHAMapSync.cpp b/src/cpp/ripple/SHAMapSync.cpp index 5c419f106..7abcf9fd8 100644 --- a/src/cpp/ripple/SHAMapSync.cpp +++ b/src/cpp/ripple/SHAMapSync.cpp @@ -135,7 +135,8 @@ bool SHAMap::getRootNode(Serializer& s, SHANodeFormat format) return true; } -bool SHAMap::addRootNode(const std::vector& rootNode, SHANodeFormat format, SHAMapSyncFilter* filter) +SMAddNode SHAMap::addRootNode(const std::vector& rootNode, SHANodeFormat format, + SHAMapSyncFilter* filter) { boost::recursive_mutex::scoped_lock sl(mLock); @@ -143,12 +144,12 @@ bool SHAMap::addRootNode(const std::vector& rootNode, SHANodeForm if (root->getNodeHash().isNonZero()) { cLog(lsTRACE) << "got root node, already have one"; - return true; + return SMAddNode::okay(); } SHAMapTreeNode::pointer node = boost::make_shared(SHAMapNode(), rootNode, 0, format); if (!node) - return false; + return SMAddNode::invalid(); #ifdef DEBUG node->dump(); @@ -170,10 +171,10 @@ bool SHAMap::addRootNode(const std::vector& rootNode, SHANodeForm filter->gotNode(*root, root->getNodeHash(), s.peekData(), root->getType()); } - return true; + return SMAddNode::useful(); } -bool SHAMap::addRootNode(const uint256& hash, const std::vector& rootNode, SHANodeFormat format, +SMAddNode SHAMap::addRootNode(const uint256& hash, const std::vector& rootNode, SHANodeFormat format, SHAMapSyncFilter* filter) { boost::recursive_mutex::scoped_lock sl(mLock); @@ -183,14 +184,12 @@ bool SHAMap::addRootNode(const uint256& hash, const std::vector& { cLog(lsTRACE) << "got root node, already have one"; assert(root->getNodeHash() == hash); - return true; + return SMAddNode::okay(); } SHAMapTreeNode::pointer node = boost::make_shared(SHAMapNode(), rootNode, 0, format); - if (!node) - return false; - if (node->getNodeHash() != hash) - return false; + if (!node || node->getNodeHash() != hash) + return SMAddNode::invalid(); returnNode(root, true); root = node; @@ -207,42 +206,42 @@ bool SHAMap::addRootNode(const uint256& hash, const std::vector& filter->gotNode(*root, root->getNodeHash(), s.peekData(), root->getType()); } - return true; + return SMAddNode::useful(); } -bool SHAMap::addKnownNode(const SHAMapNode& node, const std::vector& rawNode, +SMAddNode SHAMap::addKnownNode(const SHAMapNode& node, const std::vector& rawNode, SHAMapSyncFilter* filter) { // return value: true=okay, false=error assert(!node.isRoot()); if (!isSynching()) { cLog(lsINFO) << "AddKnownNode while not synching"; - return true; + return SMAddNode::okay(); } boost::recursive_mutex::scoped_lock sl(mLock); if (checkCacheNode(node)) - return true; + return SMAddNode::okay(); std::stack stack = getStack(node.getNodeID(), true, true); if (stack.empty()) { cLog(lsWARNING) << "AddKnownNode with empty stack"; - return false; + return SMAddNode::invalid(); } SHAMapTreeNode::pointer iNode = stack.top(); if (!iNode) { // we should always have a root assert(false); - return true; + return SMAddNode::invalid(); } if (iNode->isLeaf() || (iNode->getDepth() >= node.getDepth())) { cLog(lsTRACE) << "got inner node, already had it (late)"; - return true; + return SMAddNode::okay(); } if (iNode->getDepth() != (node.getDepth() - 1)) @@ -250,25 +249,25 @@ bool SHAMap::addKnownNode(const SHAMapNode& node, const std::vector(node, rawNode, mSeq, snfWIRE); if (hash != newNode->getNodeHash()) // these aren't the droids we're looking for - return false; + return SMAddNode::invalid(); if (filter) { @@ -279,7 +278,7 @@ bool SHAMap::addKnownNode(const SHAMapNode& node, const std::vectorisLeaf()) - return true; // only a leaf can fill a branch + return SMAddNode::useful(); // only a leaf can fill a branch // did this new leaf cause its parents to fill up do @@ -294,11 +293,11 @@ bool SHAMap::addKnownNode(const SHAMapNode& node, const std::vectorgetChildNodeID(i), iNode->getChildHash(i), false); if (nextNode->isInner() && !nextNode->isFullBelow()) - return true; + return SMAddNode::useful(); } catch (SHAMapMissingNode&) { - return true; + return SMAddNode::useful(); } } iNode->setFullBelow(); @@ -306,7 +305,7 @@ bool SHAMap::addKnownNode(const SHAMapNode& node, const std::vectorisFullBelow()) clearSynching(); - return true; + return SMAddNode::useful(); } bool SHAMap::deepCompare(SHAMap& other) @@ -486,6 +485,8 @@ BOOST_AUTO_TEST_CASE( SHAMapSync_test ) cLog(lsFATAL) << "Didn't get root node " << gotNodes.size(); BOOST_FAIL("NodeSize"); } + + SMAddNode node(); if (!destination.addRootNode(*gotNodes.begin(), snfWIRE, NULL)) { cLog(lsFATAL) << "AddRootNode fails"; From b4e7d8c5c39ec08080024fb684dd0cd2edfceb25 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Wed, 21 Nov 2012 09:49:00 -0800 Subject: [PATCH 11/11] Proof of work message structures --- src/cpp/ripple/ripple.proto | 49 ++++++++++++++++++++++++++++--------- 1 file changed, 37 insertions(+), 12 deletions(-) diff --git a/src/cpp/ripple/ripple.proto b/src/cpp/ripple/ripple.proto index 5ffbb657d..250ebf5ac 100644 --- a/src/cpp/ripple/ripple.proto +++ b/src/cpp/ripple/ripple.proto @@ -5,6 +5,7 @@ enum MessageType { mtHELLO = 1; mtERROR_MSG = 2; mtPING = 3; + mtPOW = 4; // network presence detection mtGET_CONTACTS = 10; @@ -32,20 +33,44 @@ enum MessageType { } -// Sent on connect +// empty message (or just result) = request proof of work +// token, iterations, target, challenge = give proof of work challenge +// token, response = show proof of work +// token, result = result of pow attempt +message TMProofWork +{ + optional string token = 1; + optional uint32 iterations = 2; + optional bytes target = 3; + optional bytes challenge = 4; + optional bytes response = 5; + enum POWResult + { + powrOK = 0; + powrREUSED = 1; + powrEXPIRED = 2; // You took too long solving + powrTOOEASY = 3; // Difficulty went way up, sorry + powrINVALID = 4; + powrDISCONNECT = 5; // We are disconnecting + } + optional POWResult result = 6; +} + +// Sent on connect message TMHello { - required uint32 protoVersion = 1; - required uint32 protoVersionMin = 2; - required bytes nodePublic = 3; - required bytes nodeProof = 4; - optional string fullVersion = 5; - optional uint64 netTime = 6; - optional uint32 ipv4Port = 7; - optional uint32 ledgerIndex = 8; - optional bytes ledgerClosed = 9; // our last closed ledger - optional bytes ledgerPrevious = 10; // the ledger before the last closed ledger - optional bool nodePrivate = 11; // Request to not forward IP. + required uint32 protoVersion = 1; + required uint32 protoVersionMin = 2; + required bytes nodePublic = 3; + required bytes nodeProof = 4; + optional string fullVersion = 5; + optional uint64 netTime = 6; + optional uint32 ipv4Port = 7; + optional uint32 ledgerIndex = 8; + optional bytes ledgerClosed = 9; // our last closed ledger + optional bytes ledgerPrevious = 10; // the ledger before the last closed ledger + optional bool nodePrivate = 11; // Request to not forward IP. + optional TMProofWork proofOfWork = 12; // request/provide proof of work }