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) 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-example.cfg similarity index 93% rename from rippled.cfg rename to rippled-example.cfg index c86e2324b..0bbd0f5dd 100644 --- a/rippled.cfg +++ b/rippled-example.cfg @@ -1,6 +1,8 @@ # # 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. @@ -19,8 +21,7 @@ # # Example: ripple.com # -# [unl_default]: -# XXX This should be called: [validators_file] +# [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 @@ -75,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. @@ -83,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 8a665ff13..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" @@ -27,7 +28,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" @@ -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)) @@ -292,8 +298,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..2caf47abf 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. @@ -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. 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/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/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/Peer.cpp b/src/cpp/ripple/Peer.cpp index 76e396b3e..fcca1754d 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) @@ -1417,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); } @@ -1510,6 +1527,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 +1544,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..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); @@ -49,6 +55,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/ProofOfWork.cpp b/src/cpp/ripple/ProofOfWork.cpp index 724362059..1e4ab5d9b 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,32 @@ void ProofOfWorkGenerator::sweep() } while(1); } +void ProofOfWorkGenerator::loadHigh() +{ + 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() +{ + time_t now = time(NULL); + + boost::mutex::scoped_lock sl(mLock); + if (mLastDifficultyChange == now) + return; + if (mPowEntry == 0) + return; + --mPowEntry; + mLastDifficultyChange = now; +} + struct PowEntry { const char *target; @@ -256,6 +285,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 diff --git a/src/cpp/ripple/RPCHandler.cpp b/src/cpp/ripple/RPCHandler.cpp index a9564872c..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); @@ -1640,7 +1657,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/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); 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"; 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 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 "'."; 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)); } } diff --git a/src/cpp/ripple/ripple.proto b/src/cpp/ripple/ripple.proto index 6d2292436..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 { } +// 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 + 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 } diff --git a/validators.txt b/validators-example.txt similarity index 100% rename from validators.txt rename to validators-example.txt