diff --git a/src/ConnectionPool.cpp b/src/ConnectionPool.cpp index a75220930..a4828beda 100644 --- a/src/ConnectionPool.cpp +++ b/src/ConnectionPool.cpp @@ -83,7 +83,15 @@ bool ConnectionPool::savePeer(const std::string& strIp, int iPort, char code) { db->executeSQL(str(boost::format("INSERT INTO PeerIps (IpPort,Score,Source) values (%s,0,'%c');") % ipPort % code)); bNew = true; - }// else we already had this peer + } + else + { + // We already had this peer. + // We will eventually verify its address if it is possible. + // YYY If it is vsInbound, then we might make verification immediate so we can connect back sooner if the connection + // is lost. + nothing(); + } } else { @@ -442,8 +450,8 @@ bool ConnectionPool::peerScanSet(const std::string& strIp, int iPort) boost::posix_time::ptime tpNow = boost::posix_time::second_clock::universal_time(); boost::posix_time::ptime tpNext = tpNow + boost::posix_time::seconds(iInterval); - Log(lsINFO) << str(boost::format("Pool: Scan: schedule create: %s %s (next %s, delay=%s)") - % mScanIp % mScanPort % tpNext % iInterval); + Log(lsINFO) << str(boost::format("Pool: Scan: schedule create: %s %s (next %s, delay=%d)") + % mScanIp % mScanPort % tpNext % (tpNext-tpNow).total_seconds()); db->executeSQL(str(boost::format("UPDATE PeerIps SET ScanNext=%d,ScanInterval=%d WHERE IpPort=%s;") % iToSeconds(tpNext) @@ -457,10 +465,9 @@ bool ConnectionPool::peerScanSet(const std::string& strIp, int iPort) // Scan connection terminated, already scheduled for retry. boost::posix_time::ptime tpNow = boost::posix_time::second_clock::universal_time(); boost::posix_time::ptime tpNext = ptFromSeconds(db->getInt("ScanNext")); - int iInterval = (tpNext-tpNow).seconds(); - Log(lsINFO) << str(boost::format("Pool: Scan: schedule exists: %s %s (next %s, delay=%s)") - % mScanIp % mScanPort % tpNext % iInterval); + Log(lsINFO) << str(boost::format("Pool: Scan: schedule exists: %s %s (next %s, delay=%d)") + % mScanIp % mScanPort % tpNext % (tpNext-tpNow).total_seconds()); } } else @@ -531,15 +538,23 @@ void ConnectionPool::peerVerified(Peer::pointer peer) { if (mScanning && mScanning == peer) { + // Scan completed successfully. std::string strIp = peer->getIP(); int iPort = peer->getPort(); std::string strIpPort = str(boost::format("%s %d") % strIp % iPort); - Log(lsINFO) << str(boost::format("Pool: Scan: connected: %s %s %s (scan off)") % ADDRESS_SHARED(peer) % strIp % iPort); + Log(lsINFO) << str(boost::format("Pool: Scan: connected: %s %s %s (scanned)") % ADDRESS_SHARED(peer) % strIp % iPort); - // Scan completed successfully. + if (peer->getNodePublic() == theApp->getWallet().getNodePublic()) { + // Talking to ourself. We will just back off. This lets us maybe advertise our outside address. + + nothing(); // Do nothing, leave scheduled scanning. + } + else + { + // Talking with a different peer. ScopedLock sl(theApp->getWalletDB()->getDBLock()); Database *db=theApp->getWalletDB()->getDB(); @@ -628,10 +643,10 @@ void ConnectionPool::scanRefresh() tpNext = tpNow + boost::posix_time::seconds(iInterval); - iInterval *= 2; + Log(lsINFO) << str(boost::format("Pool: Scan: Now: %s %s (next %s, delay=%d)") + % mScanIp % mScanPort % tpNext % (tpNext-tpNow).total_seconds()); - Log(lsINFO) << str(boost::format("Pool: Scan: Now: %s %s (next %s, delay=%s)") - % mScanIp % mScanPort % tpNext % iInterval); + iInterval *= 2; { ScopedLock sl(theApp->getWalletDB()->getDBLock()); @@ -653,8 +668,8 @@ void ConnectionPool::scanRefresh() } else { - Log(lsINFO) << str(boost::format("Pool: Scan: Next: %s (next %s, delay=%s)") - % strIpPort % tpNext % (tpNext-tpNow).seconds()); + Log(lsINFO) << str(boost::format("Pool: Scan: Next: %s (next %s, delay=%d)") + % strIpPort % tpNext % (tpNext-tpNow).total_seconds()); mScanTimer.expires_at(tpNext); mScanTimer.async_wait(boost::bind(&ConnectionPool::scanHandler, this, _1)); diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index 30c1b404f..e3408ee76 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -323,7 +323,10 @@ void LedgerConsensus::statusChange(newcoin::NodeEvent event, Ledger::pointer led { // Send a node status change message to our peers newcoin::TMStatusChange s; if (!mHaveCorrectLCL) + { + Log(lsTRACE) << "Telling peers we have lost sync"; s.set_newevent(newcoin::neLOST_SYNC); + } else { s.set_newevent(event); diff --git a/src/NetworkOPs.cpp b/src/NetworkOPs.cpp index bad18d886..f92a016f9 100644 --- a/src/NetworkOPs.cpp +++ b/src/NetworkOPs.cpp @@ -261,10 +261,10 @@ void NetworkOPs::setStateTimer(int sec) class ValidationCount { public: - int trustedValidations, untrustedValidations, nodesUsing; + int trustedValidations, nodesUsing; NewcoinAddress highNode; - ValidationCount() : trustedValidations(0), untrustedValidations(0), nodesUsing(0) { ; } + ValidationCount() : trustedValidations(0), nodesUsing(0) { ; } bool operator>(const ValidationCount& v) { if (trustedValidations > v.trustedValidations) return true; @@ -362,44 +362,40 @@ bool NetworkOPs::checkLastClosedLedger(const std::vector& peerLis // node is using. THis is kind of fundamental. boost::unordered_map ledgers; + + { + boost::unordered_map current = theApp->getValidations().getCurrentValidations(); + for (boost::unordered_map::iterator it = current.begin(), end = current.end(); it != end; ++it) + ledgers[it->first].trustedValidations += it->second; + } + + Ledger::pointer currentClosed = mLedgerMaster->getClosedLedger(); + uint256 closedLedger = currentClosed->getHash(); + ValidationCount& ourVC = ledgers[closedLedger]; + ++ourVC.nodesUsing; + ourVC.highNode = theApp->getWallet().getNodePublic(); + for (std::vector::const_iterator it = peerList.begin(), end = peerList.end(); it != end; ++it) { if (!*it) { Log(lsDEBUG) << "NOP::CS Dead pointer in peer list"; } - else + else if ((*it)->isConnected()) { uint256 peerLedger = (*it)->getClosedLedgerHash(); if (!!peerLedger) { - // FIXME: If we have this ledger, don't count it if it's too far past its close time ValidationCount& vc = ledgers[peerLedger]; - if (vc.nodesUsing == 0) - { - theApp->getValidations().getValidationCount(peerLedger, true, - vc.trustedValidations, vc.untrustedValidations); - Log(lsTRACE) << peerLedger.GetHex() << " has " << vc.trustedValidations << - " trusted validations and " << vc.untrustedValidations << " untrusted"; - } if ((vc.nodesUsing == 0) || ((*it)->getNodePublic() > vc.highNode)) vc.highNode = (*it)->getNodePublic(); ++vc.nodesUsing; } + else Log(lsTRACE) << "Connected peer announces no LCL"; } } - Ledger::pointer currentClosed = mLedgerMaster->getClosedLedger(); - uint256 closedLedger = currentClosed->getHash(); - ValidationCount& ourVC = ledgers[closedLedger]; - if (ourVC.nodesUsing == 0) - { - ourVC.highNode = theApp->getWallet().getNodePublic(); - theApp->getValidations().getValidationCount(closedLedger, true, - ourVC.trustedValidations, ourVC.untrustedValidations); - } - ++ourVC.nodesUsing; - ValidationCount bestVC = ourVC; + ValidationCount bestVC = ledgers[closedLedger]; // 3) Is there a network ledger we'd like to switch to? If so, do we have it? bool switchLedgers = false; @@ -407,8 +403,7 @@ bool NetworkOPs::checkLastClosedLedger(const std::vector& peerLis it != end; ++it) { Log(lsTRACE) << "L: " << it->first.GetHex() << - " t=" << it->second.trustedValidations << ", u=" << it->second.untrustedValidations << - ", n=" << it->second.nodesUsing; + " t=" << it->second.trustedValidations << ", n=" << it->second.nodesUsing; if (it->second > bestVC) { bestVC = it->second; @@ -580,7 +575,10 @@ void NetworkOPs::endConsensus() std::vector peerList = theApp->getConnectionPool().getPeerVector(); for (std::vector::const_iterator it = peerList.begin(), end = peerList.end(); it != end; ++it) if (*it && ((*it)->getClosedLedgerHash() == deadLedger)) + { + Log(lsTRACE) << "Killing obsolete peer status"; (*it)->cycleStatus(); + } mConsensus = boost::shared_ptr(); } diff --git a/src/Peer.cpp b/src/Peer.cpp index c30f30e45..24fb29388 100644 --- a/src/Peer.cpp +++ b/src/Peer.cpp @@ -23,7 +23,7 @@ #define NODE_VERIFY_SECONDS 15 Peer::Peer(boost::asio::io_service& io_service, boost::asio::ssl::context& ctx) : - mConnected(false), + mHelloed(false), mDetaching(false), mSocketSsl(io_service, ctx), mVerifyTimer(io_service) @@ -40,19 +40,22 @@ void Peer::handle_write(const boost::system::error_code& error, size_t bytes_tra mSendingPacket = PackedMessage::pointer(); - if (error) + if (mDetaching) { - if (!mDetaching) - { - Log(lsINFO) << "Peer: Write: Error: " << ADDRESS(this) << ": bytes=" << bytes_transferred << ": " << error.category().name() << ": " << error.message() << ": " << error; + // Ignore write requests when detatching. + nothing(); + } + else if (error) + { + Log(lsINFO) << "Peer: Write: Error: " << ADDRESS(this) << ": bytes=" << bytes_transferred << ": " << error.category().name() << ": " << error.message() << ": " << error; - detach("hw"); - } - - } else if (!mSendQ.empty()) + detach("hw"); + } + else if (!mSendQ.empty()) { PackedMessage::pointer packet = mSendQ.front(); - if(packet) + + if (packet) { sendPacketForce(packet); mSendQ.pop_front(); @@ -71,7 +74,6 @@ void Peer::setIpPort(const std::string& strIP, int iPort) void Peer::detach(const char *rsn) { - if (!mDetaching) { mDetaching = true; // Race is ok. @@ -81,17 +83,10 @@ void Peer::detach(const char *rsn) << rsn << ": " << (mNodePublic.isValid() ? mNodePublic.humanNodePublic() : "-") << " " << getIP() << " " << getPort(); - boost::system::error_code ecCancel; - - (void) mVerifyTimer.cancel(); - mSendQ.clear(); - // We may close more than once. - boost::system::error_code ecShutdown; - getSocket().shutdown(boost::asio::ip::tcp::socket::shutdown_both, ecShutdown); - - getSocket().close(); + (void) mVerifyTimer.cancel(); + mSocketSsl.async_shutdown(boost::bind(&Peer::handleShutdown, shared_from_this(), boost::asio::placeholders::error)); if (mNodePublic.isValid()) { @@ -264,11 +259,15 @@ void Peer::connected(const boost::system::error_code& error) void Peer::sendPacketForce(PackedMessage::pointer packet) { - mSendingPacket = packet; - boost::asio::async_write(mSocketSsl, boost::asio::buffer(packet->getBuffer()), - boost::bind(&Peer::handle_write, shared_from_this(), - boost::asio::placeholders::error, - boost::asio::placeholders::bytes_transferred)); + if (!mDetaching) + { + mSendingPacket = packet; + + boost::asio::async_write(mSocketSsl, boost::asio::buffer(packet->getBuffer()), + boost::bind(&Peer::handle_write, shared_from_this(), + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred)); + } } void Peer::sendPacket(PackedMessage::pointer packet) @@ -288,10 +287,14 @@ void Peer::sendPacket(PackedMessage::pointer packet) void Peer::start_read_header() { - mReadbuf.clear(); - mReadbuf.resize(HEADER_SIZE); - boost::asio::async_read(mSocketSsl, boost::asio::buffer(mReadbuf), - boost::bind(&Peer::handle_read_header, shared_from_this(), boost::asio::placeholders::error)); + if (!mDetaching) + { + mReadbuf.clear(); + mReadbuf.resize(HEADER_SIZE); + + boost::asio::async_read(mSocketSsl, boost::asio::buffer(mReadbuf), + boost::bind(&Peer::handle_read_header, shared_from_this(), boost::asio::placeholders::error)); + } } void Peer::start_read_body(unsigned msg_len) @@ -299,15 +302,24 @@ void Peer::start_read_body(unsigned msg_len) // m_readbuf already contains the header in its first HEADER_SIZE // bytes. Expand it to fit in the body as well, and start async // read into the body. - // - mReadbuf.resize(HEADER_SIZE + msg_len); - boost::asio::async_read(mSocketSsl, boost::asio::buffer(&mReadbuf[HEADER_SIZE], msg_len), - boost::bind(&Peer::handle_read_body, shared_from_this(), boost::asio::placeholders::error)); + + if (!mDetaching) + { + mReadbuf.resize(HEADER_SIZE + msg_len); + + boost::asio::async_read(mSocketSsl, boost::asio::buffer(&mReadbuf[HEADER_SIZE], msg_len), + boost::bind(&Peer::handle_read_body, shared_from_this(), boost::asio::placeholders::error)); + } } void Peer::handle_read_header(const boost::system::error_code& error) { - if (!error) + if (mDetaching) + { + // Drop data or error if detaching. + nothing(); + } + else if (!error) { unsigned msg_len = PackedMessage::getLength(mReadbuf); // WRITEME: Compare to maximum message length, abort if too large @@ -318,7 +330,7 @@ void Peer::handle_read_header(const boost::system::error_code& error) } start_read_body(msg_len); } - else if (!mDetaching) + else { Log(lsINFO) << "Peer: Header: Error: " << ADDRESS(this) << ": " << error.category().name() << ": " << error.message() << ": " << error; detach("hrh2"); @@ -327,12 +339,17 @@ void Peer::handle_read_header(const boost::system::error_code& error) void Peer::handle_read_body(const boost::system::error_code& error) { - if (!error) + if (mDetaching) + { + // Drop data or error if detaching. + nothing(); + } + else if (!error) { processReadBuffer(); start_read_header(); } - else if (!mDetaching) + else { Log(lsINFO) << "Peer: Body: Error: " << ADDRESS(this) << ": " << error.category().name() << ": " << error.message() << ": " << error; detach("hrb"); @@ -349,7 +366,7 @@ void Peer::processReadBuffer() // std::cerr << "Peer::processReadBuffer: " << mIpPort.first << " " << mIpPort.second << std::endl; // If connected and get a mtHELLO or if not connected and get a non-mtHELLO, wrong message was sent. - if (mConnected == (type == newcoin::mtHELLO)) + if (mHelloed == (type == newcoin::mtHELLO)) { Log(lsWARNING) << "Wrong message type: " << type; detach("prb1"); @@ -593,7 +610,7 @@ void Peer::recvHello(newcoin::TMHello& packet) } // Consider us connected. No longer accepting mtHELLO. - mConnected = true; + mHelloed = true; // XXX Set timer: connection is in grace period to be useful. // XXX Set timer: connection idle (idle may vary depending on connection type.) @@ -840,8 +857,10 @@ void Peer::recvStatus(newcoin::TMStatusChange& packet) if (packet.newevent() == newcoin::neLOST_SYNC) { + Log(lsTRACE) << "peer has lost sync"; mPreviousLedgerHash.zero(); mClosedLedgerHash.zero(); + return; } if (packet.has_ledgerhash() && (packet.ledgerhash().size() == (256 / 8))) { // a peer has changed ledgers @@ -849,7 +868,12 @@ void Peer::recvStatus(newcoin::TMStatusChange& packet) mClosedLedgerTime = ptFromSeconds(packet.networktime()); Log(lsTRACE) << "peer LCL is " << mClosedLedgerHash.GetHex(); } - else mClosedLedgerHash.zero(); + else + { + Log(lsTRACE) << "peer has no ledger hash"; + mClosedLedgerHash.zero(); + } + if (packet.has_previousledgerhash() && packet.previousledgerhash().size() == (256 / 8)) { memcpy(mPreviousLedgerHash.begin(), packet.previousledgerhash().data(), 256 / 8); diff --git a/src/Peer.h b/src/Peer.h index f4ecc82d3..3150532ef 100644 --- a/src/Peer.h +++ b/src/Peer.h @@ -31,7 +31,7 @@ public: private: bool mClientConnect; // In process of connecting as client. - bool mConnected; // True, if hello accepted. + bool mHelloed; // True, if hello accepted. bool mDetaching; // True, if detaching. NewcoinAddress mNodePublic; // Node public key of peer. ipPort mIpPort; @@ -58,6 +58,8 @@ protected: Peer(boost::asio::io_service& io_service, boost::asio::ssl::context& ctx); + void handleShutdown(const boost::system::error_code& error) { ; } + void handle_write(const boost::system::error_code& error, size_t bytes_transferred); void handle_read_header(const boost::system::error_code& error); void handle_read_body(const boost::system::error_code& error); @@ -128,7 +130,7 @@ public: void punishPeer(PeerPunish pp); Json::Value getJson(); - bool isConnected() const { return mConnected; } + bool isConnected() const { return mHelloed && !mDetaching; } //static PackedMessage::pointer createFullLedger(Ledger::pointer ledger); static PackedMessage::pointer createLedgerProposal(Ledger::pointer ledger); diff --git a/src/SerializedObject.cpp b/src/SerializedObject.cpp index 123781cbe..8f465936f 100644 --- a/src/SerializedObject.cpp +++ b/src/SerializedObject.cpp @@ -485,6 +485,17 @@ STAmount STObject::getValueFieldAmount(SOE_Field field) const return *cf; } +STPathSet STObject::getValueFieldPathSet(SOE_Field field) const +{ + const SerializedType* rf = peekAtPField(field); + if (!rf) throw std::runtime_error("Field not found"); + SerializedTypeID id = rf->getSType(); + if (id == STI_NOTPRESENT) return STPathSet(); // optional field not present + const STPathSet *cf = dynamic_cast(rf); + if (!cf) throw std::runtime_error("Wrong field type"); + return *cf; +} + STVector256 STObject::getValueFieldV256(SOE_Field field) const { const SerializedType* rf = peekAtPField(field); diff --git a/src/SerializedObject.h b/src/SerializedObject.h index ab115e125..ab82ef284 100644 --- a/src/SerializedObject.h +++ b/src/SerializedObject.h @@ -167,6 +167,7 @@ public: std::vector getValueFieldVL(SOE_Field field) const; std::vector getValueFieldTL(SOE_Field field) const; STAmount getValueFieldAmount(SOE_Field field) const; + STPathSet getValueFieldPathSet(SOE_Field field) const; STVector256 getValueFieldV256(SOE_Field field) const; void setValueFieldU8(SOE_Field field, unsigned char); diff --git a/src/SerializedTransaction.h b/src/SerializedTransaction.h index 2ec1bced8..59f1650ca 100644 --- a/src/SerializedTransaction.h +++ b/src/SerializedTransaction.h @@ -89,6 +89,7 @@ public: std::vector getITFieldVL(SOE_Field field) const { return mInnerTxn.getValueFieldVL(field); } std::vector getITFieldTL(SOE_Field field) const { return mInnerTxn.getValueFieldTL(field); } STAmount getITFieldAmount(SOE_Field field) const { return mInnerTxn.getValueFieldAmount(field); } + STPathSet getITFieldPathSet(SOE_Field field) const { return mInnerTxn.getValueFieldPathSet(field); } void setITFieldU8(SOE_Field field, unsigned char v) { return mInnerTxn.setValueFieldU8(field, v); } void setITFieldU16(SOE_Field field, uint16 v) { return mInnerTxn.setValueFieldU16(field, v); } diff --git a/src/TransactionEngine.cpp b/src/TransactionEngine.cpp index 2235ff1bd..4c5841d33 100644 --- a/src/TransactionEngine.cpp +++ b/src/TransactionEngine.cpp @@ -1,6 +1,11 @@ +// +// XXX Should make sure all fields and are recognized on a transactions. +// XXX Make sure fee is claimed for failed transactions. +// #include "TransactionEngine.h" +#include #include #include "../json/writer.h" @@ -1008,10 +1013,15 @@ TransactionEngineResult TransactionEngine::doPasswordSet(const SerializedTransac TransactionEngineResult TransactionEngine::doPayment(const SerializedTransaction& txn, std::vector& accounts, - const uint160& srcAccountID) + const uint160& uSrcAccountID) { - uint32 txFlags = txn.getFlags(); - uint160 uDstAccountID = txn.getITFieldAccount(sfDestination); + uint32 txFlags = txn.getFlags(); + uint160 uDstAccountID = txn.getITFieldAccount(sfDestination); + // XXX Could also be ripple if direct credit lines. + bool bRipple = txn.getITFieldPresent(sfPaths); + bool bCreate = !!(txFlags & tfCreateAccount); + STAmount saAmount = txn.getITFieldAmount(sfAmount); + STAmount saSrcBalance = accounts[0].second->getIValueFieldAmount(sfBalance); if (!uDstAccountID) { @@ -1019,38 +1029,30 @@ TransactionEngineResult TransactionEngine::doPayment(const SerializedTransaction return tenINVALID; } // XXX Only bad if no currency conversion in between through other people's offer. - else if (srcAccountID == uDstAccountID) + else if (uSrcAccountID == uDstAccountID) { std::cerr << "doPayment: Invalid transaction: Source account is the same as destination." << std::endl; return tenINVALID; } - bool bCreate = !!(txFlags & tfCreateAccount); - - uint160 uCurrency; - if (txn.getITFieldPresent(sfCurrency)) - { - uCurrency = txn.getITFieldH160(sfCurrency); - if (!uCurrency) - { - std::cerr << "doPayment: Invalid transaction: " SYSTEM_CURRENCY_CODE " explicitly specified." << std::endl; - return tenEXPLICITXNC; - } - } + // XXX Allow ripple to create. LedgerStateParms qry = lepNONE; SLE::pointer sleDst = mLedger->getAccountRoot(qry, uDstAccountID); if (!sleDst) { // Destination account does not exist. - if (bCreate && !!uCurrency) + // XXX Also make sure non-ripple dest if creating. + if (bCreate && !saAmount.isNative()) { - std::cerr << "doPayment: Invalid transaction: Create account may only fund XBC." << std::endl; - return tenCREATEXNC; + std::cerr << "doPayment: Invalid transaction: Create account may only fund XNS." << std::endl; + + return tenCREATEXNS; } else if (!bCreate) { std::cerr << "doPayment: Delay transaction: Destination account does not exist." << std::endl; + return terNO_DST; } @@ -1067,6 +1069,7 @@ TransactionEngineResult TransactionEngine::doPayment(const SerializedTransaction else if (bCreate) { std::cerr << "doPayment: Invalid transaction: Account already created." << std::endl; + return terCREATED; } else @@ -1074,28 +1077,68 @@ TransactionEngineResult TransactionEngine::doPayment(const SerializedTransaction accounts.push_back(std::make_pair(taaMODIFY, sleDst)); } - STAmount saAmount = txn.getITFieldAmount(sfAmount); - - if (!uCurrency) + if (!bRipple) { - STAmount saSrcBalance = accounts[0].second->getIValueFieldAmount(sfBalance); + // Direct XNS payment. + if (!saAmount.isNative()) + { + std::cerr << "doPayment: Invalid transaction: direct " SYSTEM_CURRENCY_CODE " required." << std::endl; + + return tenDIRECT_XNS_ONLY; + } if (saSrcBalance < saAmount) { std::cerr << "doPayment: Delay transaction: Insufficent funds." << std::endl; + return terUNFUNDED; } accounts[0].second->setIFieldAmount(sfBalance, saSrcBalance - saAmount); accounts[1].second->setIFieldAmount(sfBalance, accounts[1].second->getIValueFieldAmount(sfBalance) + saAmount); - } - else - { - // WRITEME: Handle non-native currencies, paths - return tenUNKNOWN; + + return terSUCCESS; } - return terSUCCESS; + // + // Try direct ripple first. + // + + uint160 uDstCurrency = saAmount.getCurrency(); + + qry = lepNONE; + SLE::pointer sleRippleState = mLedger->getRippleState(qry, uSrcAccountID, uDstAccountID, uDstCurrency); + + if (sleRippleState) + { + // There is a direct relationship. + + } + + STPathSet spsPaths = txn.getITFieldPathSet(sfPaths); + + // XXX If we are parsing for determing forwarding check maximum path count. + if (!spsPaths.getPathCount()) + { + std::cerr << "doPayment: Invalid transaction: No paths." << std::endl; + + return tenRIPPLE_EMPTY; + } +#if 0 + std::vector spPath; + + BOOST_FOREACH(std::vector& spPath, spsPaths) + { + + std::cerr << "doPayment: Implementation error: Not implemented." << std::endl; + + return tenUNKNOWN; + } +#endif + + std::cerr << "doPayment: Delay transaction: No ripple paths could be satisfied." << std::endl; + + return terBAD_RIPPLE; } TransactionEngineResult TransactionEngine::doTransitSet(const SerializedTransaction& st, std::vector&) diff --git a/src/TransactionEngine.h b/src/TransactionEngine.h index 9104f8a9c..805c87954 100644 --- a/src/TransactionEngine.h +++ b/src/TransactionEngine.h @@ -14,20 +14,23 @@ enum TransactionEngineResult // Malformed: Fee claimed tenGEN_IN_USE = -300, // Generator already in use. - tenCREATEXNC, // Can not specify non XNC for Create. - tenEXPLICITXNC, // XNC is used by default, don't specify it. + tenCREATEXNS, // Can not specify non XNS for Create. + tenEXPLICITXNS, // XNS is used by default, don't specify it. tenDST_NEEDED, // Destination not specified. tenDST_IS_SRC, // Destination may not be source. tenBAD_GEN_AUTH, // Not authorized to claim generator. tenBAD_ADD_AUTH, // Not authorized to add account. tenBAD_CLAIM_ID, // Malformed. tenBAD_SET_ID, // Malformed. + tenDIRECT_XNS_ONLY, // Direct payments are non-ripple XNS only. + tenRIPPLE_EMPTY, // PathSet with no paths. // Invalid: Ledger won't allow. tenCLAIMED = -200, // Can not claim a previously claimed account. tenCREATED, // Can't add an already created account. tenMSG_SET, // Can't change a message key. tenBAD_AUTH_MASTER, // Auth for unclaimed account needs correct master key. + tenBAD_RIPPLE, // Ledger prevents ripple from succeeding. // Other tenFAILED = -100, // Something broke horribly @@ -61,6 +64,7 @@ enum TransactionEngineResult terFUNDS_SPENT, // Can't set password, password set funds already spent. terUNCLAIMED, // Can not use an unclaimed account. terBAD_AUTH, // Transaction's public key is not authorized. + terBAD_RIPPLE, // No ripple path can be satisfied. }; enum TransactionEngineParams diff --git a/src/ValidationCollection.cpp b/src/ValidationCollection.cpp index 5061d0d13..a1ed90546 100644 --- a/src/ValidationCollection.cpp +++ b/src/ValidationCollection.cpp @@ -13,7 +13,7 @@ bool ValidationCollection::addValidation(SerializedValidation::pointer val) val->setTrusted(); uint64 now = theApp->getOPs().getNetworkTimeNC(); uint64 valClose = val->getCloseTime(); - if ((now > valClose) && (now < (valClose + 2 * LEDGER_INTERVAL))) + if ((now > valClose) && (now < (valClose + LEDGER_INTERVAL))) isCurrent = true; else Log(lsWARNING) << "Received stale validation now=" << now << ", close=" << valClose; @@ -74,3 +74,30 @@ void ValidationCollection::getValidationCount(const uint256& ledger, bool curren } } } + +boost::unordered_map ValidationCollection::getCurrentValidations() +{ + uint64 now = theApp->getOPs().getNetworkTimeNC(); + boost::unordered_map ret; + + { + boost::mutex::scoped_lock sl(mValidationLock); + boost::unordered_map::iterator it = mCurrentValidations.begin(); + while (it != mCurrentValidations.end()) + { + if (now > (it->second->getCloseTime() + LEDGER_INTERVAL)) + { + Log(lsTRACE) << "Erasing validation for " << it->second->getLedgerHash().GetHex(); + it = mCurrentValidations.erase(it); + } + else + { + Log(lsTRACE) << "Counting validation for " << it->second->getLedgerHash().GetHex(); + ++ret[it->second->getLedgerHash()]; + ++it; + } + } + } + + return ret; +} diff --git a/src/ValidationCollection.h b/src/ValidationCollection.h index 62540f585..7df9c91bb 100644 --- a/src/ValidationCollection.h +++ b/src/ValidationCollection.h @@ -24,6 +24,7 @@ public: bool addValidation(SerializedValidation::pointer); ValidationSet getValidations(const uint256& ledger); void getValidationCount(const uint256& ledger, bool currentOnly, int& trusted, int& untrusted); + boost::unordered_map getCurrentValidations(); }; #endif