diff --git a/src/Config.h b/src/Config.h index 7c900523f5..d5fc3ad732 100644 --- a/src/Config.h +++ b/src/Config.h @@ -12,6 +12,7 @@ #define SYSTEM_NAME "newcoin" #define SYSTEM_CURRENCY_CODE "XNS" #define SYSTEM_CURRENCY_PRECISION 6 +#define SYSTEM_CURRENCY_CODE_RIPPLE "XNR" #define SYSTEM_CURRENCY_GIFT 1000ull #define SYSTEM_CURRENCY_USERS 100000000ull @@ -54,8 +55,6 @@ public: std::vector VALIDATORS; // Validators from newcoind.cfg. std::vector IPS; // Peer IPs from newcoind.cfg. - - // Network parameters int NETWORK_START_TIME; // The Unix time we start ledger 0. int TRANSACTION_FEE_BASE; @@ -88,7 +87,6 @@ public: std::string RPC_PASSWORD; bool RPC_ALLOW_REMOTE; - // Validation NewcoinAddress VALIDATION_SEED; diff --git a/src/HttpsClient.cpp b/src/HttpsClient.cpp index 26f027870a..987869e099 100644 --- a/src/HttpsClient.cpp +++ b/src/HttpsClient.cpp @@ -67,7 +67,7 @@ void HttpsClient::httpsNext() { mDeadline.async_wait( boost::bind( - &HttpsClient::handleDeadline, + &HttpsClient::ShandleDeadline, shared_from_this(), boost::asio::placeholders::error)); } @@ -78,7 +78,7 @@ void HttpsClient::httpsNext() mResolver.async_resolve(*mQuery, boost::bind( - &HttpsClient::handleResolve, + &HttpsClient::ShandleResolve, shared_from_this(), boost::asio::placeholders::error, boost::asio::placeholders::iterator)); @@ -149,7 +149,7 @@ void HttpsClient::handleResolve( mSocketSsl.lowest_layer(), itrEndpoint, boost::bind( - &HttpsClient::handleConnect, + &HttpsClient::ShandleConnect, shared_from_this(), boost::asio::placeholders::error)); } @@ -183,7 +183,7 @@ void HttpsClient::handleConnect(const boost::system::error_code& ecResult) if (!mShutdown) { mSocketSsl.async_handshake(boost::asio::ssl::stream::client, - boost::bind(&HttpsClient::handleRequest, + boost::bind(&HttpsClient::ShandleRequest, shared_from_this(), boost::asio::placeholders::error)); } @@ -219,7 +219,7 @@ void HttpsClient::handleRequest(const boost::system::error_code& ecResult) boost::asio::async_write( mSocketSsl, mRequest, - boost::bind(&HttpsClient::handleWrite, + boost::bind(&HttpsClient::ShandleWrite, shared_from_this(), boost::asio::placeholders::error)); } @@ -244,7 +244,7 @@ void HttpsClient::handleWrite(const boost::system::error_code& ecResult) mSocketSsl, mResponse, boost::asio::transfer_all(), - boost::bind(&HttpsClient::handleData, + boost::bind(&HttpsClient::ShandleData, shared_from_this(), boost::asio::placeholders::error)); } diff --git a/src/HttpsClient.h b/src/HttpsClient.h index 930ffeaad3..bebe57a3e3 100644 --- a/src/HttpsClient.h +++ b/src/HttpsClient.h @@ -19,6 +19,8 @@ class HttpsClient : public boost::enable_shared_from_this { private: + typedef boost::shared_ptr pointer; + boost::asio::ssl::context mCtx; boost::asio::ip::tcp::resolver mResolver; boost::shared_ptr mQuery; @@ -38,16 +40,28 @@ private: boost::posix_time::time_duration mTimeout; void handleDeadline(const boost::system::error_code& ecResult); + static void ShandleDeadline(pointer This, const boost::system::error_code& ecResult) + { This->handleDeadline(ecResult); } - void handleResolve( - const boost::system::error_code& ecResult, - boost::asio::ip::tcp::resolver::iterator endpoint_iterator - ); + void handleResolve(const boost::system::error_code& ecResult, boost::asio::ip::tcp::resolver::iterator endpoint_iterator); + static void ShandleResolve(pointer This, const boost::system::error_code& ecResult, boost::asio::ip::tcp::resolver::iterator endpoint_iterator) + { This->handleResolve(ecResult, endpoint_iterator); } void handleConnect(const boost::system::error_code& ecResult); + static void ShandleConnect(pointer This, const boost::system::error_code& ecResult) + { This->handleConnect(ecResult); } + void handleRequest(const boost::system::error_code& ecResult); + static void ShandleRequest(pointer This, const boost::system::error_code& ecResult) + { This->handleRequest(ecResult); } + void handleWrite(const boost::system::error_code& ecResult); + static void ShandleWrite(pointer This, const boost::system::error_code& ecResult) + { This->handleWrite(ecResult); } + void handleData(const boost::system::error_code& ecResult); + static void ShandleData(pointer This, const boost::system::error_code& ecResult) + { This->handleData(ecResult); } void parseData(); void httpsNext(); diff --git a/src/NewcoinAddress.h b/src/NewcoinAddress.h index ffe1045095..c591d1b0d7 100644 --- a/src/NewcoinAddress.h +++ b/src/NewcoinAddress.h @@ -74,6 +74,9 @@ public: static NewcoinAddress createAccountID(const uint160& uiAccountID); + static std::string createHumanAccountID(const uint160& uiAccountID) + { return createAccountID(uiAccountID).humanAccountID(); } + static std::string createHumanAccountID(const std::vector& vPrivate) { return createAccountPrivate(vPrivate).humanAccountID(); } diff --git a/src/Peer.cpp b/src/Peer.cpp index eb8616a744..7c6741dfbb 100644 --- a/src/Peer.cpp +++ b/src/Peer.cpp @@ -88,7 +88,7 @@ void Peer::detach(const char *rsn) mSendQ.clear(); (void) mVerifyTimer.cancel(); - mSocketSsl.async_shutdown(boost::bind(&Peer::handleShutdown, shared_from_this(), boost::asio::placeholders::error)); + mSocketSsl.async_shutdown(boost::bind(&Peer::sHandleShutdown, shared_from_this(), boost::asio::placeholders::error)); if (mNodePublic.isValid()) { @@ -165,7 +165,7 @@ void Peer::connect(const std::string strIp, int iPort) else { mVerifyTimer.expires_from_now(boost::posix_time::seconds(NODE_VERIFY_SECONDS), err); - mVerifyTimer.async_wait(boost::bind(&Peer::handleVerifyTimer, shared_from_this(), boost::asio::placeholders::error)); + mVerifyTimer.async_wait(boost::bind(&Peer::sHandleVerifyTimer, shared_from_this(), boost::asio::placeholders::error)); if (err) { @@ -183,7 +183,7 @@ void Peer::connect(const std::string strIp, int iPort) getSocket(), itrEndpoint, boost::bind( - &Peer::handleConnect, + &Peer::sHandleConnect, shared_from_this(), boost::asio::placeholders::error, boost::asio::placeholders::iterator)); @@ -223,7 +223,7 @@ void Peer::handleConnect(const boost::system::error_code& error, boost::asio::ip mSocketSsl.set_verify_mode(boost::asio::ssl::verify_none); mSocketSsl.async_handshake(boost::asio::ssl::stream::client, - boost::bind(&Peer::handleStart, shared_from_this(), boost::asio::placeholders::error)); + boost::bind(&Peer::sHandleStart, shared_from_this(), boost::asio::placeholders::error)); } } @@ -250,7 +250,7 @@ void Peer::connected(const boost::system::error_code& error) mSocketSsl.set_verify_mode(boost::asio::ssl::verify_none); mSocketSsl.async_handshake(boost::asio::ssl::stream::server, - boost::bind(&Peer::handleStart, shared_from_this(), boost::asio::placeholders::error)); + boost::bind(&Peer::sHandleStart, shared_from_this(), boost::asio::placeholders::error)); } else if (!mDetaching) { @@ -267,7 +267,7 @@ 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::bind(&Peer::sHandle_write, shared_from_this(), boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); } @@ -296,7 +296,7 @@ void Peer::start_read_header() 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)); + boost::bind(&Peer::sHandle_read_header, shared_from_this(), boost::asio::placeholders::error)); } } @@ -311,7 +311,7 @@ void Peer::start_read_body(unsigned msg_len) 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)); + boost::bind(&Peer::sHandle_read_body, shared_from_this(), boost::asio::placeholders::error)); } } diff --git a/src/Peer.h b/src/Peer.h index 3223632904..f06a8c3faa 100644 --- a/src/Peer.h +++ b/src/Peer.h @@ -24,10 +24,15 @@ typedef std::pair ipPort; class Peer : public boost::enable_shared_from_this { public: + typedef boost::shared_ptr pointer; + static const int psbGotHello = 0, psbSentHello = 1, psbInMap = 2, psbTrusted = 3; static const int psbNoLedgers = 4, psbNoTransactions = 5, psbDownLevel = 6; void handleConnect(const boost::system::error_code& error, boost::asio::ip::tcp::resolver::iterator it); + static void sHandleConnect(Peer::pointer ptr, const boost::system::error_code& error, + boost::asio::ip::tcp::resolver::iterator it) + { ptr->handleConnect(error, it); } private: bool mClientConnect; // In process of connecting as client. @@ -47,7 +52,12 @@ private: boost::asio::deadline_timer mVerifyTimer; void handleStart(const boost::system::error_code& ecResult); + static void sHandleStart(Peer::pointer ptr, const boost::system::error_code& ecResult) + { ptr->handleStart(ecResult); } + void handleVerifyTimer(const boost::system::error_code& ecResult); + static void sHandleVerifyTimer(Peer::pointer ptr, const boost::system::error_code& ecResult) + { ptr->handleVerifyTimer(ecResult); } protected: @@ -60,10 +70,21 @@ protected: Peer(boost::asio::io_service& io_service, boost::asio::ssl::context& ctx); void handleShutdown(const boost::system::error_code& error) { ; } + static void sHandleShutdown(Peer::pointer ptr, const boost::system::error_code& error) + { ptr->handleShutdown(error); } void handle_write(const boost::system::error_code& error, size_t bytes_transferred); + static void sHandle_write(Peer::pointer ptr, const boost::system::error_code& error, size_t bytes_transferred) + { ptr->handle_write(error, bytes_transferred); } + void handle_read_header(const boost::system::error_code& error); + static void sHandle_read_header(Peer::pointer ptr, const boost::system::error_code& error) + { ptr->handle_read_header(error); } + void handle_read_body(const boost::system::error_code& error); + static void sHandle_read_body(Peer::pointer ptr, const boost::system::error_code& error) + { ptr->handle_read_body(error); } + void processReadBuffer(); void start_read_header(); void start_read_body(unsigned msg_len); @@ -97,7 +118,6 @@ protected: void getSessionCookie(std::string& strDst); public: - typedef boost::shared_ptr pointer; //bool operator == (const Peer& other); diff --git a/src/RPCServer.cpp b/src/RPCServer.cpp index b6fc77327e..e18926f1e2 100644 --- a/src/RPCServer.cpp +++ b/src/RPCServer.cpp @@ -52,7 +52,6 @@ Json::Value RPCServer::RPCError(int iError) { rpcLGR_IDXS_INVALID, "lgrIdxsInvalid", "Ledger indexes invalid." }, { rpcLGR_IDX_MALFORMED, "lgrIdxMalformed", "Ledger index malformed." }, { rpcLGR_NOT_FOUND, "lgrNotFound", "Ledger not found." }, - { rpcMUST_SEND_XNS, "mustSendXns", "Can only send XNS to accounts which are not created." }, { rpcNICKNAME_MALFORMED,"nicknameMalformed","Nickname is malformed." }, { rpcNICKNAME_MISSING, "nicknameMissing", "Nickname does not exist." }, { rpcNICKNAME_PERM, "nicknamePerm", "Account does not control nickname." }, @@ -100,7 +99,7 @@ void RPCServer::connected() else mRole=GUEST; mSocket.async_read_some(boost::asio::buffer(mReadBuffer), - boost::bind(&RPCServer::handle_read, shared_from_this(), + boost::bind(&RPCServer::Shandle_read, shared_from_this(), boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); } @@ -127,7 +126,7 @@ void RPCServer::handle_read(const boost::system::error_code& e, else { // not done keep reading mSocket.async_read_some(boost::asio::buffer(mReadBuffer), - boost::bind(&RPCServer::handle_read, shared_from_this(), + boost::bind(&RPCServer::Shandle_read, shared_from_this(), boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); } @@ -301,15 +300,27 @@ Json::Value RPCServer::authorize(const uint256& uLedger, // Find the index of the account from the master generator, so we can generate the public and private keys. NewcoinAddress naMasterAccountPublic; - unsigned int iIndex = -1; // Compensate for initial increment. + unsigned int iIndex = 0; // Compensate for initial increment. + bool bFound = false; // XXX Stop after Config.account_probe_max // Don't look at ledger entries to determine if the account exists. Don't want to leak to thin server that these accounts are // related. - do { - ++iIndex; + while (!bFound && iIndex != theConfig.ACCOUNT_PROBE_MAX) + { naMasterAccountPublic.setAccountPublic(naMasterGenerator, iIndex); - } while (naSrcAccountID.getAccountID() != naMasterAccountPublic.getAccountID()); + + Log(lsINFO) << "authorize: " << iIndex << " : " << naMasterAccountPublic.humanAccountID() << " : " << naSrcAccountID.humanAccountID(); + + bFound = naSrcAccountID.getAccountID() == naMasterAccountPublic.getAccountID(); + if (!bFound) + ++iIndex; + } + + if (!bFound) + { + return RPCError(rpcACT_NOT_FOUND); + } // Use the regular generator to determine the associated public and private keys. NewcoinAddress naGenerator = NewcoinAddress::createGeneratorPublic(naRegularSeed); @@ -319,9 +330,9 @@ Json::Value RPCServer::authorize(const uint256& uLedger, if (asSrc->bHaveAuthorizedKey() && (asSrc->getAuthorizedKey().getAccountID() != naAccountPublic.getAccountID())) { - std::cerr << "iIndex: " << iIndex << std::endl; - std::cerr << "sfAuthorizedKey: " << strHex(asSrc->getAuthorizedKey().getAccountID()) << std::endl; - std::cerr << "naAccountPublic: " << strHex(naAccountPublic.getAccountID()) << std::endl; + // std::cerr << "iIndex: " << iIndex << std::endl; + // std::cerr << "sfAuthorizedKey: " << strHex(asSrc->getAuthorizedKey().getAccountID()) << std::endl; + // std::cerr << "naAccountPublic: " << strHex(naAccountPublic.getAccountID()) << std::endl; return RPCError(rpcPASSWD_CHANGED); } @@ -330,6 +341,8 @@ Json::Value RPCServer::authorize(const uint256& uLedger, if (saSrcBalance < saFee) { + Log(lsINFO) << "authorize: Insufficent funds for fees: fee=" << saFee.getText() << " balance=" << saSrcBalance.getText(); + return RPCError(rpcINSUF_FUNDS); } else @@ -1177,15 +1190,33 @@ Json::Value RPCServer::doSend(const Json::Value& params) if (params.size() < 6) saSrcAmount = saDstAmount; - if (saSrcBalance < saDstAmount) + // Do a few simple checks. + if (!saSrcAmount.isNative()) { + Log(lsINFO) << "doSend: Ripple"; + + nothing(); + } + else if (!saSrcBalance.isPositive()) + { + // No native currency to send. + Log(lsINFO) << "doSend: No native currency to send: " << saSrcBalance.getText(); + + return RPCError(rpcINSUF_FUNDS); + } + else if (saDstAmount.isNative() && saSrcAmount < saDstAmount) + { + // Not enough native currency. + + Log(lsINFO) << "doSend: Insufficent funds: src=" << saSrcAmount.getText() << " dst=" << saDstAmount.getText(); + return RPCError(rpcINSUF_FUNDS); } Transaction::pointer trans; if (asDst) { - // Ordinary send. + // Destination exists, ordinary send. STPathSet spPaths; @@ -1200,13 +1231,9 @@ Json::Value RPCServer::doSend(const Json::Value& params) saSrcAmount, spPaths); } - else if (!saDstAmount.isNative()) - { - return RPCError(rpcMUST_SEND_XNS); - } else { - // Create and send. + // Create destination and send. trans = Transaction::sharedCreate( naAccountPublic, naAccountPrivate, @@ -1215,7 +1242,7 @@ Json::Value RPCServer::doSend(const Json::Value& params) saFee, 0, // YYY No source tag naDstAccountID, - saDstAmount); // Initial funds in XNC. + saDstAmount); // Initial funds in XNS. } (void) mNetOps->processTransaction(trans); @@ -2070,7 +2097,7 @@ void RPCServer::sendReply() { //std::cout << "RPC reply: " << mReplyStr << std::endl; boost::asio::async_write(mSocket, boost::asio::buffer(mReplyStr), - boost::bind(&RPCServer::handle_write, shared_from_this(), + boost::bind(&RPCServer::Shandle_write, shared_from_this(), boost::asio::placeholders::error)); } @@ -2099,7 +2126,7 @@ void RPCServer::handle_write(const boost::system::error_code& e) mIncomingRequest.headers.clear(); mRequestParser.reset(); mSocket.async_read_some(boost::asio::buffer(mReadBuffer), - boost::bind(&RPCServer::handle_read, shared_from_this(), + boost::bind(&RPCServer::Shandle_read, shared_from_this(), boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); } diff --git a/src/RPCServer.h b/src/RPCServer.h index 39535c7c05..da478fbb8c 100644 --- a/src/RPCServer.h +++ b/src/RPCServer.h @@ -34,7 +34,6 @@ public: rpcACT_NOT_FOUND, rpcINSUF_FUNDS, rpcLGR_NOT_FOUND, - rpcMUST_SEND_XNS, rpcNICKNAME_MISSING, rpcNO_ACCOUNT, rpcPASSWD_CHANGED, @@ -71,6 +70,8 @@ public: Json::Value RPCError(int iError); + typedef boost::shared_ptr pointer; + private: typedef Json::Value (RPCServer::*doFuncPtr)(const Json::Value ¶ms); enum { @@ -96,9 +97,13 @@ private: RPCServer(const RPCServer&); // no implementation RPCServer& operator=(const RPCServer&); // no implementation - void handle_write(const boost::system::error_code& error); + void handle_write(const boost::system::error_code& ec); + static void Shandle_write(pointer This, const boost::system::error_code& ec) + { This->handle_write(ec); } - void handle_read(const boost::system::error_code& e, std::size_t bytes_transferred); + void handle_read(const boost::system::error_code& ec, std::size_t bytes_transferred); + static void Shandle_read(pointer This, const boost::system::error_code& ec, std::size_t bytes_transferred) + { This->handle_read(ec, bytes_transferred); } std::string handleRequest(const std::string& requestStr); void sendReply(); @@ -166,8 +171,6 @@ private: Json::Value doLogin(const Json::Value& params); public: - typedef boost::shared_ptr pointer; - static pointer create(boost::asio::io_service& io_service, NetworkOPs* mNetOps) { return pointer(new RPCServer(io_service, mNetOps)); diff --git a/src/RippleState.cpp b/src/RippleState.cpp index 736a1ecc83..0b319faab7 100644 --- a/src/RippleState.cpp +++ b/src/RippleState.cpp @@ -15,9 +15,7 @@ RippleState::RippleState(SerializedLedgerEntry::pointer ledgerEntry) : mBalance = mLedgerEntry->getIValueFieldAmount(sfBalance); - // YYY Should never fail. - if (mLowID.isValid() && mHighID.isValid()) - mValid = true; + mValid = true; } void RippleState::setViewAccount(const NewcoinAddress& naView) @@ -27,7 +25,7 @@ void RippleState::setViewAccount(const NewcoinAddress& naView) if (bViewLowestNew != mViewLowest) { mViewLowest = bViewLowestNew; - mBalance.changeSign(); + mBalance.negate(); } } diff --git a/src/SerializedTypes.cpp b/src/SerializedTypes.cpp index fabccd678b..209cc12623 100644 --- a/src/SerializedTypes.cpp +++ b/src/SerializedTypes.cpp @@ -297,7 +297,7 @@ STPathSet* STPathSet::construct(SerializerIterator& s, const char *name) switch(s.get8()) { case STPathElement::typeEnd: - if(path.empty()) + if (path.empty()) { if (!paths.empty()) throw std::runtime_error("empty last path"); @@ -335,16 +335,17 @@ int STPathSet::getLength() const Json::Value STPath::getJson(int) const { Json::Value ret(Json::arrayValue); - for (std::vector::const_iterator it = mPath.begin(), end = mPath.end(); it != end; ++it) + + BOOST_FOREACH(std::vector::const_iterator::value_type it, mPath) { - switch (it->getNodeType()) + switch (it.getNodeType()) { case STPathElement::typeAccount: { Json::Value elem(Json::objectValue); - NewcoinAddress account; - account.setAccountID(it->getNode()); - elem["account"] = account.humanAccountID(); + + elem["account"] = NewcoinAddress::createHumanAccountID(it.getNode()); + ret.append(elem); break; } @@ -352,7 +353,9 @@ Json::Value STPath::getJson(int) const case STPathElement::typeOffer: { Json::Value elem(Json::objectValue); - elem["offer"] = it->getNode().GetHex(); + + elem["offer"] = it.getNode().GetHex(); + ret.append(elem); break; } @@ -360,14 +363,17 @@ Json::Value STPath::getJson(int) const default: throw std::runtime_error("Unknown path element"); } } + return ret; } Json::Value STPathSet::getJson(int options) const { Json::Value ret(Json::arrayValue); - for (std::vector::const_iterator it = value.begin(), end = value.end(); it!=end; ++it) - ret.append(it->getJson(options)); + + BOOST_FOREACH(std::vector::const_iterator::value_type it, value) + ret.append(it.getJson(options)); + return ret; } @@ -375,22 +381,22 @@ std::string STPath::getText() const { std::string ret("["); bool first = true; - for (std::vector::const_iterator it = mPath.begin(), end = mPath.end(); it != end; ++it) + + BOOST_FOREACH(std::vector::const_iterator::value_type it, mPath) { if (!first) ret += ", "; - switch (it->getNodeType()) + switch (it.getNodeType()) { case STPathElement::typeAccount: { - NewcoinAddress account; - account.setAccountID(it->getNode()); - ret += account.humanAccountID(); + ret += NewcoinAddress::createHumanAccountID(it.getNode()); break; } + case STPathElement::typeOffer: { ret += "Offer("; - ret += it->getNode().GetHex(); + ret += it.getNode().GetHex(); ret += ")"; break; } @@ -399,6 +405,7 @@ std::string STPath::getText() const } first = false; } + return ret + "]"; } @@ -406,14 +413,15 @@ std::string STPathSet::getText() const { std::string ret("{"); bool firstPath = true; - for (std::vector::const_iterator it = value.begin(), end = value.end(); it != end; ++it) + + BOOST_FOREACH(std::vector::const_iterator::value_type it, value) { if (!firstPath) { ret += ", "; firstPath = false; } - ret += it->getText(); + ret += it.getText(); } return ret + "}"; } @@ -421,14 +429,16 @@ std::string STPathSet::getText() const void STPathSet::add(Serializer& s) const { bool firstPath = true; - for (std::vector::const_iterator pit = value.begin(), pend = value.end(); pit != pend; ++pit) + + BOOST_FOREACH(std::vector::const_iterator::value_type pit, value) { if (!firstPath) { s.add8(STPathElement::typeBoundary); firstPath = false; } - for (std::vector::const_iterator eit = pit->begin(), eend = pit->end(); eit != eend; ++eit) + + for (std::vector::const_iterator eit = pit.begin(), eend = pit.end(); eit != eend; ++eit) { s.add8(eit->getNodeType()); s.add160(eit->getNode()); diff --git a/src/SerializedTypes.h b/src/SerializedTypes.h index e562de31a6..04462f2452 100644 --- a/src/SerializedTypes.h +++ b/src/SerializedTypes.h @@ -206,10 +206,12 @@ class STAmount : public SerializedType // Low 56 bits are value, legal range is 10^15 to (10^16 - 1) inclusive protected: - uint160 mCurrency; - uint64 mValue; - int mOffset; - bool mIsNative, mIsNegative; + uint160 mCurrency; + + uint64 mValue; + int mOffset; + bool mIsNative; // True for native stamps, ripple stamps are not native. + bool mIsNegative; void canonicalize(); STAmount* duplicate() const { return new STAmount(*this); } @@ -277,7 +279,7 @@ public: bool isGEZero() const { return !mIsNegative; } operator bool() const { return !isZero(); } - void changeSign() { if (!isZero()) mIsNegative = !mIsNegative; } + void negate() { if (!isZero()) mIsNegative = !mIsNegative; } void zero() { mOffset = mIsNative ? -100 : 0; mValue = 0; mIsNegative = false; } const uint160& getCurrency() const { return mCurrency; } @@ -504,6 +506,8 @@ public: int getNodeType() const { return mType; } bool isAccount() const { return mType == typeAccount; } bool isOffer() const { return mType == typeOffer; } + + // Nodes are either an account ID or a offer prefix. Offer prefixs denote a class of offers. const uint160& getNode() const { return mNode; } void setType(int type) { mType = type; } diff --git a/src/TransactionEngine.cpp b/src/TransactionEngine.cpp index 18a30aaa7a..d21010c4ce 100644 --- a/src/TransactionEngine.cpp +++ b/src/TransactionEngine.cpp @@ -24,49 +24,51 @@ bool transResultInfo(TransactionEngineResult terCode, std::string& strToken, std const char* cpToken; const char* cpHuman; } transResultInfoA[] = { - { tenGEN_IN_USE, "tenGEN_IN_USE", "Generator already in use." }, - { tenCREATEXNS, "tenCREATEXNS", "Can not specify non XNS for Create." }, - { tenEXPLICITXNS, "tenEXPLICITXNS", "XNS is used by default, don't specify it." }, - { tenDST_NEEDED, "tenDST_NEEDED", "Destination not specified." }, - { tenDST_IS_SRC, "tenDST_IS_SRC", "Destination may not be source." }, - { tenBAD_GEN_AUTH, "tenBAD_GEN_AUTH", "Not authorized to claim generator." }, - { tenBAD_ADD_AUTH, "tenBAD_ADD_AUTH", "Not authorized to add account." }, - { tenBAD_CLAIM_ID, "tenBAD_CLAIM_ID", "Malformed." }, - { tenBAD_SET_ID, "tenBAD_SET_ID", "Malformed." }, - { tenDIRECT_XNS_ONLY, "tenDIRECT_XNS_ONLY", "Direct payments are non-ripple XNS only." }, - { tenRIPPLE_EMPTY, "tenRIPPLE_EMPTY", "PathSet with no paths." }, - { tenCLAIMED, "tenCLAIMED", "Can not claim a previously claimed account." }, - { tenCREATED, "tenCREATED", "Can't add an already created account." }, - { tenMSG_SET, "tenMSG_SET", "Can't change a message key." }, + { tenBAD_ADD_AUTH, "tenBAD_ADD_AUTH", "Not authorized to add account." }, + { tenBAD_AMOUNT, "tenBAD_AMOUNT", "Can only send positive amounts." }, { tenBAD_AUTH_MASTER, "tenBAD_AUTH_MASTER", "Auth for unclaimed account needs correct master key." }, - { tenBAD_RIPPLE, "tenBAD_RIPPLE", "Ledger prevents ripple from succeeding." }, - { terALREADY, "terALREADY", "The exact transaction was already in this ledger" }, - { tenFAILED, "tenFAILED", "Something broke horribly" }, + { tenBAD_CLAIM_ID, "tenBAD_CLAIM_ID", "Malformed." }, + { tenBAD_GEN_AUTH, "tenBAD_GEN_AUTH", "Not authorized to claim generator." }, + { tenBAD_RIPPLE, "tenBAD_RIPPLE", "Ledger prevents ripple from succeeding." }, + { tenBAD_SET_ID, "tenBAD_SET_ID", "Malformed." }, + { tenCLAIMED, "tenCLAIMED", "Can not claim a previously claimed account." }, + { tenCREATED, "tenCREATED", "Can't add an already created account." }, + { tenCREATEXNS, "tenCREATEXNS", "Can not specify non XNS for Create." }, + { tenDST_IS_SRC, "tenDST_IS_SRC", "Destination may not be source." }, + { tenDST_NEEDED, "tenDST_NEEDED", "Destination not specified." }, + { tenEXPLICITXNS, "tenEXPLICITXNS", "XNS is used by default, don't specify it." }, + { tenFAILED, "tenFAILED", "Something broke horribly" }, + { tenGEN_IN_USE, "tenGEN_IN_USE", "Generator already in use." }, + { tenINSUF_FEE_P, "tenINSUF_FEE_P", "fee totally insufficient" }, + { tenINVALID, "tenINVALID", "The transaction is ill-formed" }, + { tenMSG_SET, "tenMSG_SET", "Can't change a message key." }, + { tenREDUNDANT, "tenREDUNDANT", "Sends same currency to self." }, + { tenRIPPLE_EMPTY, "tenRIPPLE_EMPTY", "PathSet with no paths." }, { tenUNKNOWN, "tenUNKNOWN", "The transactions requires logic not implemented yet" }, - { tenINSUF_FEE_P, "tenINSUF_FEE_P", "fee totally insufficient" }, - { tenINVALID, "tenINVALID", "The transaction is ill-formed" }, - { terSUCCESS, "terSUCCESS", "The transaction was applied" }, + { terALREADY, "terALREADY", "The exact transaction was already in this ledger" }, + { terBAD_AUTH, "terBAD_AUTH", "Transaction's public key is not authorized." }, + { terBAD_RIPPLE, "terBAD_RIPPLE", "No ripple path can be satisfied." }, { terBAD_SEQ, "terBAD_SEQ", "This sequence number should be zero for prepaid transactions." }, - { terCREATED, "terCREATED", "Can not create a previously created account." }, - { terDIR_FULL, "terDIR_FULL", "Can not add entry to full dir." }, - { terINSUF_FEE_B, "terINSUF_FEE_B", "Account balance can't pay fee" }, - { terINSUF_FEE_T, "terINSUF_FEE_T", "fee insufficient now (account doesn't exist, network load)" }, - { terNODE_NOT_FOUND, "terNODE_NOT_FOUND", "Can not delete a dir node." }, - { terNODE_NOT_MENTIONED, "terNODE_NOT_MENTIONED", "?"}, - { terNODE_NO_ROOT, "terNODE_NO_ROOT", "?"}, - { terNO_ACCOUNT, "terNO_ACCOUNT", "The source account does not exist" }, - { terNO_DST, "terNO_DST", "The destination does not exist" }, - { terNO_PATH, "terNO_PATH", "No path existed or met transaction/balance requirements" }, - { terPAST_LEDGER, "terPAST_LEDGER", "The transaction expired and can't be applied" }, - { terPAST_SEQ, "terPAST_SEQ", "This sequence number has already past" }, - { terPRE_SEQ, "terPRE_SEQ", "Missing/inapplicable prior transaction" }, - { terUNFUNDED, "terUNFUNDED", "Source account had insufficient balance for transaction." }, - { terNO_LINE_NO_ZERO, "terNO_LINE_NO_ZERO", "Can't zero non-existant line, destination might make it." }, - { terSET_MISSING_DST, "terSET_MISSING_DST", "Can't set password, destination missing." }, + { terCREATED, "terCREATED", "Can not create a previously created account." }, + { terDIR_FULL, "terDIR_FULL", "Can not add entry to full dir." }, { terFUNDS_SPENT, "terFUNDS_SPENT", "Can't set password, password set funds already spent." }, - { terUNCLAIMED, "terUNCLAIMED", "Can not use an unclaimed account." }, - { terBAD_AUTH, "terBAD_AUTH", "Transaction's public key is not authorized." }, - { terBAD_RIPPLE, "terBAD_RIPPLE", "No ripple path can be satisfied." }, + { terINSUF_FEE_B, "terINSUF_FEE_B", "Account balance can't pay fee" }, + { terINSUF_FEE_T, "terINSUF_FEE_T", "fee insufficient now (account doesn't exist, network load)" }, + { terNODE_NOT_FOUND, "terNODE_NOT_FOUND", "Can not delete a dir node." }, + { terNODE_NOT_MENTIONED, "terNODE_NOT_MENTIONED", "?" }, + { terNODE_NO_ROOT, "terNODE_NO_ROOT", "?" }, + { terNO_ACCOUNT, "terNO_ACCOUNT", "The source account does not exist" }, + { terNO_DST, "terNO_DST", "The destination does not exist" }, + { terNO_LINE_NO_ZERO, "terNO_LINE_NO_ZERO", "Can't zero non-existant line, destination might make it." }, + { terNO_PATH, "terNO_PATH", "No path existed or met transaction/balance requirements" }, + { terOVER_LIMIT, "terOVER_LIMIT", "Over limit." }, + { terPAST_LEDGER, "terPAST_LEDGER", "The transaction expired and can't be applied" }, + { terPAST_SEQ, "terPAST_SEQ", "This sequence number has already past" }, + { terPRE_SEQ, "terPRE_SEQ", "Missing/inapplicable prior transaction" }, + { terSET_MISSING_DST, "terSET_MISSING_DST", "Can't set password, destination missing." }, + { terSUCCESS, "terSUCCESS", "The transaction was applied" }, + { terUNCLAIMED, "terUNCLAIMED", "Can not use an unclaimed account." }, + { terUNFUNDED, "terUNFUNDED", "Source account had insufficient balance for transaction." }, }; int iIndex = NUMBER(transResultInfoA); @@ -82,7 +84,11 @@ bool transResultInfo(TransactionEngineResult terCode, std::string& strToken, std return iIndex >= 0; } -// We return the uNodeDir so that on delete we can quickly know where the element is mentioned in the directory. + +// <-> accounts: Affected accounts for the transaction. +// <-- uNodeDir: For deletion, present to make dirDelete efficient. +// --> uBase: The index of the base of the directory. Nodes are based off of this. +// --> uLedgerIndex: Value to add to directory. TransactionEngineResult TransactionEngine::dirAdd( std::vector& accounts, uint64& uNodeDir, @@ -108,7 +114,6 @@ TransactionEngineResult TransactionEngine::dirAdd( sleRoot = boost::make_shared(ltDIR_ROOT); - sleRoot->setIndex(uRootIndex); Log(lsTRACE) << "dirAdd: Creating dir index: " << sleRoot->getIndex().ToString(); @@ -180,6 +185,10 @@ TransactionEngineResult TransactionEngine::dirAdd( return terSUCCESS; } +// <-> accounts: Affected accounts for the transaction. +// --> uNodeDir: Node containing entry. +// --> uBase: The index of the base of the directory. Nodes are based off of this. +// --> uLedgerIndex: Value to add to directory. TransactionEngineResult TransactionEngine::dirDelete( std::vector& accounts, const uint64& uNodeDir, @@ -880,20 +889,21 @@ TransactionEngineResult TransactionEngine::doCreditSet(const SerializedTransacti const uint160& uSrcAccountID) { TransactionEngineResult terResult = terSUCCESS; - std::cerr << "doCreditSet>" << std::endl; + Log(lsINFO) << "doCreditSet>"; // Check if destination makes sense. uint160 uDstAccountID = txn.getITFieldAccount(sfDestination); if (!uDstAccountID) { - std::cerr << "doCreditSet: Invalid transaction: Payment destination account not specifed." << std::endl; + Log(lsINFO) << "doCreditSet: Invalid transaction: Destination account not specifed."; + return tenDST_NEEDED; } - // XXX Might make sense for ripple. else if (uSrcAccountID == uDstAccountID) { - std::cerr << "doCreditSet: Invalid transaction: Source account is the same as destination." << std::endl; + Log(lsINFO) << "doCreditSet: Invalid transaction: Can not extend credit to self."; + return tenDST_IS_SRC; } @@ -901,7 +911,7 @@ TransactionEngineResult TransactionEngine::doCreditSet(const SerializedTransacti SLE::pointer sleDst = mLedger->getAccountRoot(qry, uDstAccountID); if (!sleDst) { - std::cerr << "doCreditSet: Delay transaction: Destination account does not exist." << std::endl; + Log(lsINFO) << "doCreditSet: Delay transaction: Destination account does not exist."; return terNO_DST; } @@ -911,41 +921,69 @@ TransactionEngineResult TransactionEngine::doCreditSet(const SerializedTransacti bool bSltD = uSrcAccountID < uDstAccountID; uint32 uFlags = bSltD ? lsfLowIndexed : lsfHighIndexed; STAmount saBalance(uCurrency); - bool bAddIndex; + bool bAddIndex = false; + bool bDelIndex = false; qry = lepNONE; SLE::pointer sleRippleState = mLedger->getRippleState(qry, uSrcAccountID, uDstAccountID, uCurrency); if (sleRippleState) { - bAddIndex = !(sleRippleState->getFlags() & uFlags); + // A line exists in one or more directions. +#if 0 + if (saLimitAmount.isZero()) + { + // Zeroing line. + uint160 uLowID = sleRippleState->getIValueFieldAccount(sfLowID).getAccountID(); + uint160 uHighID = sleRippleState->getIValueFieldAccount(sfHighID).getAccountID(); + bool bLow = uLowID == uSrcAccountID; + bool bHigh = uLowID == uDstAccountID; + bool bBalanceZero = sleRippleState->getIValueFieldAmount(sfBalance).isZero(); + STAmount saDstLimit = sleRippleState->getIValueFieldAmount(bSendLow ? sfLowLimit : sfHighLimit); + bool bDstLimitZero = saDstLimit.isZero(); - std::cerr << "doCreditSet: Modifying ripple line: bAddIndex=" << bAddIndex << std::endl; + assert(bLow || bHigh); - sleRippleState->setIFieldAmount(bSltD ? sfLowLimit : sfHighLimit, saLimitAmount); + if (bBalanceZero && bDstLimitZero) + { + // Zero balance and eliminating last limit. - if (bAddIndex) - sleRippleState->setFlag(uFlags); + bDelIndex = true; + terResult = dirDelete(accounts, uSrcRef, Ledger::getRippleDirIndex(uSrcAccountID), sleRippleState->getIndex()); + } + } +#endif + if (!bDelIndex) + { + bAddIndex = !(sleRippleState->getFlags() & uFlags); - accounts.push_back(std::make_pair(taaMODIFY, sleRippleState)); + sleRippleState->setIFieldAmount(bSltD ? sfLowLimit : sfHighLimit, saLimitAmount); + + if (bAddIndex) + sleRippleState->setFlag(uFlags); + + accounts.push_back(std::make_pair(taaMODIFY, sleRippleState)); + } + + Log(lsINFO) << "doCreditSet: Modifying ripple line: bAddIndex=" << bAddIndex << " bDelIndex=" << bDelIndex; } // Line does not exist. else if (saLimitAmount.isZero()) { - std::cerr << "doCreditSet: Setting non-existant ripple line to 0." << std::endl; + Log(lsINFO) << "doCreditSet: Redundant: Setting non-existant ripple line to 0."; return terNO_LINE_NO_ZERO; } else { + // Create a new ripple line. STAmount saZero(uCurrency); bAddIndex = true; sleRippleState = boost::make_shared(ltRIPPLE_STATE); sleRippleState->setIndex(Ledger::getRippleStateIndex(uSrcAccountID, uDstAccountID, uCurrency)); - std::cerr << "doCreditSet: Creating ripple line: " - << sleRippleState->getIndex().ToString() - << std::endl; + Log(lsINFO) << "doCreditSet: Creating ripple line: " + << sleRippleState->getIndex().ToString(); sleRippleState->setFlag(uFlags); sleRippleState->setIFieldAmount(sfBalance, saZero); // Zero balance in currency. @@ -959,17 +997,13 @@ TransactionEngineResult TransactionEngine::doCreditSet(const SerializedTransacti if (bAddIndex) { - // Add entries so clients can find lines. - // - Client needs to be able to walk who account has given credit to and who has account's credit. - // - Client doesn't need to know every account who has extended credit but it owed nothing. uint64 uSrcRef; // Ignored, ripple_state dirs never delete. - // XXX Verify extend is passing the right bits, not the zero bits. // XXX Make dirAdd more flexiable to take vector. terResult = dirAdd(accounts, uSrcRef, Ledger::getRippleDirIndex(uSrcAccountID), sleRippleState->getIndex()); } - std::cerr << "doCreditSet<" << std::endl; + Log(lsINFO) << "doCreditSet<"; return terResult; } @@ -1083,47 +1117,61 @@ TransactionEngineResult TransactionEngine::doPasswordSet(const SerializedTransac return result; } +// XXX Need to audit for things like setting accountID not having memory. TransactionEngineResult TransactionEngine::doPayment(const SerializedTransaction& txn, std::vector& accounts, const uint160& uSrcAccountID) { + // Ripple if source or destination is non-native or if there are paths. 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); + bool bNoRippleDirect = !!(txFlags & tfNoRippleDirect); + bool bPaths = txn.getITFieldPresent(sfPaths); + bool bMax = txn.getITFieldPresent(sfSendMax); + uint160 uDstAccountID = txn.getITFieldAccount(sfDestination); + STAmount saDstAmount = txn.getITFieldAmount(sfAmount); + STAmount saMaxAmount = bMax ? txn.getITFieldAmount(sfSendMax) : saDstAmount; + uint160 uSrcCurrency = saMaxAmount.getCurrency(); + uint160 uDstCurrency = saDstAmount.getCurrency(); if (!uDstAccountID) { - std::cerr << "doPayment: Invalid transaction: Payment destination account not specifed." << std::endl; - return tenINVALID; - } - // XXX Only bad if no currency conversion in between through other people's offer. - else if (uSrcAccountID == uDstAccountID) - { - std::cerr << "doPayment: Invalid transaction: Source account is the same as destination." << std::endl; - return tenINVALID; - } + Log(lsINFO) << "doPayment: Invalid transaction: Payment destination account not specifed."; - // XXX Allow ripple to create. + return tenDST_NEEDED; + } + else if (!saDstAmount.isPositive()) + { + Log(lsINFO) << "doPayment: Invalid transaction: bad amount: " << saDstAmount.getCurrencyHuman() << " " << saDstAmount.getText(); + + return tenBAD_AMOUNT; + } + else if (uSrcAccountID == uDstAccountID && uSrcCurrency == uDstCurrency && !bPaths) + { + Log(lsINFO) << boost::str(boost::format("doPayment: Invalid transaction: Redunant transaction: src=%s, dst=%s, src_cur=%s, dst_cur=%s") + % uSrcAccountID.ToString() + % uDstAccountID.ToString() + % uSrcCurrency.ToString() + % uDstCurrency.ToString()); + + return tenREDUNDANT; + } LedgerStateParms qry = lepNONE; SLE::pointer sleDst = mLedger->getAccountRoot(qry, uDstAccountID); if (!sleDst) { // Destination account does not exist. - // XXX Also make sure non-ripple dest if creating. - if (bCreate && !saAmount.isNative()) + if (bCreate && !saDstAmount.isNative()) { - std::cerr << "doPayment: Invalid transaction: Create account may only fund XNS." << std::endl; + // This restriction could be relaxed. + Log(lsINFO) << "doPayment: Invalid transaction: Create account may only fund XNS."; return tenCREATEXNS; } else if (!bCreate) { - std::cerr << "doPayment: Delay transaction: Destination account does not exist." << std::endl; + Log(lsINFO) << "doPayment: Delay transaction: Destination account does not exist."; return terNO_DST; } @@ -1140,7 +1188,8 @@ TransactionEngineResult TransactionEngine::doPayment(const SerializedTransaction // Destination exists. else if (bCreate) { - std::cerr << "doPayment: Invalid transaction: Account already created." << std::endl; + // Retryable: if account created this ledger, reordering might allow account to be made by this transaction. + Log(lsINFO) << "doPayment: Invalid transaction: Account already created."; return terCREATED; } @@ -1149,42 +1198,117 @@ TransactionEngineResult TransactionEngine::doPayment(const SerializedTransaction accounts.push_back(std::make_pair(taaMODIFY, sleDst)); } + bool bRipple = bPaths || bMax || !saDstAmount.isNative(); + if (!bRipple) { // Direct XNS payment. - if (!saAmount.isNative()) - { - std::cerr << "doPayment: Invalid transaction: direct " SYSTEM_CURRENCY_CODE " required." << std::endl; + STAmount saSrcXNSBalance = accounts[0].second->getIValueFieldAmount(sfBalance); - return tenDIRECT_XNS_ONLY; - } - - if (saSrcBalance < saAmount) + if (saSrcXNSBalance < saDstAmount) { - std::cerr << "doPayment: Delay transaction: Insufficent funds." << std::endl; + // Transaction might succeed, if applied in a different order. + Log(lsINFO) << "doPayment: Delay transaction: Insufficent funds."; return terUNFUNDED; } - accounts[0].second->setIFieldAmount(sfBalance, saSrcBalance - saAmount); - accounts[1].second->setIFieldAmount(sfBalance, accounts[1].second->getIValueFieldAmount(sfBalance) + saAmount); + accounts[0].second->setIFieldAmount(sfBalance, saSrcXNSBalance - saDstAmount); + accounts[1].second->setIFieldAmount(sfBalance, accounts[1].second->getIValueFieldAmount(sfBalance) + saDstAmount); return terSUCCESS; } // - // Try direct ripple first. + // Ripple payment // - uint160 uDstCurrency = saAmount.getCurrency(); - - qry = lepNONE; - SLE::pointer sleRippleState = mLedger->getRippleState(qry, uSrcAccountID, uDstAccountID, uDstCurrency); - - if (sleRippleState) + // Try direct ripple first. + if (!bNoRippleDirect && uSrcAccountID != uDstAccountID && uSrcCurrency == uDstCurrency) { - // There is a direct relationship. + qry = lepNONE; + SLE::pointer sleRippleState = mLedger->getRippleState(qry, uSrcAccountID, uDstAccountID, uDstCurrency); + if (sleRippleState) + { + // There is a direct credit-line of some direction. + // - We can always pay IOUs back. + // - We can issue IOUs to the limit. + // XXX Not implemented: + // - Give preference to pushing out IOUs over sender credit limit. + // - Give preference to pushing out IOUs to creating them. + // - Create IOUs as last resort. + uint160 uLowID = sleRippleState->getIValueFieldAccount(sfLowID).getAccountID(); + uint160 uHighID = sleRippleState->getIValueFieldAccount(sfHighID).getAccountID(); + bool bSendHigh = uLowID == uSrcAccountID && uHighID == uDstAccountID; + bool bSendLow = uLowID == uDstAccountID && uHighID == uSrcAccountID; + // Flag we need if we end up owing IOUs. + uint32 uFlags = bSendHigh ? lsfLowIndexed : lsfHighIndexed; + + assert(bSendLow || bSendHigh); + + STAmount saDstLimit = sleRippleState->getIValueFieldAmount(bSendLow ? sfLowLimit : sfHighLimit); + + STAmount saDstBalance = sleRippleState->getIValueFieldAmount(sfBalance); + if (bSendHigh) + { + // Put balance in dst terms. + saDstBalance.negate(); + } + + saDstBalance += saDstAmount; + if (saDstBalance > saDstLimit) + { + // Would exceed credit limit. + // YYY Note: in the future could push out other credits to make payment fit. + + Log(lsINFO) << "doPayment: Delay transaction: Over limit: proposed balance=" + << saDstBalance.getText() + << " limit=" + << saDstLimit.getText(); + + return terOVER_LIMIT; + } + + if (saDstBalance.isZero()) + { + // XXX May be able to delete indexes for credit limits which are zero. + nothing(); + } + else if (saDstBalance.isNegative()) + { + // dst still has outstanding IOUs, sle already indexed. + nothing(); + } + // src has outstanding IOUs, sle should be indexed. + else if (! (sleRippleState->getFlags() & uFlags)) + { + // Need to add index. + TransactionEngineResult terResult = terSUCCESS; + uint64 uSrcRef; // Ignored, ripple_state dirs never delete. + + terResult = dirAdd(accounts, + uSrcRef, + Ledger::getRippleDirIndex(uSrcAccountID), // The source ended up owing. + sleRippleState->getIndex()); // Adding current entry. + + if (terSUCCESS != terResult) + return terResult; + + sleRippleState->setFlag(uFlags); // Note now indexed. + } + + if (bSendHigh) + { + // Put balance in low terms. + saDstBalance.negate(); + } + + sleRippleState->setIFieldAmount(sfBalance, saDstBalance); + accounts.push_back(std::make_pair(taaMODIFY, sleRippleState)); + + return terSUCCESS; + } } STPathSet spsPaths = txn.getITFieldPathSet(sfPaths); @@ -1192,7 +1316,7 @@ TransactionEngineResult TransactionEngine::doPayment(const SerializedTransaction // XXX If we are parsing for determing forwarding check maximum path count. if (!spsPaths.getPathCount()) { - std::cerr << "doPayment: Invalid transaction: No paths." << std::endl; + Log(lsINFO) << "doPayment: Invalid transaction: No paths."; return tenRIPPLE_EMPTY; } @@ -1202,13 +1326,13 @@ TransactionEngineResult TransactionEngine::doPayment(const SerializedTransaction BOOST_FOREACH(std::vector& spPath, spsPaths) { - std::cerr << "doPayment: Implementation error: Not implemented." << std::endl; + Log(lsINFO) << "doPayment: Implementation error: Not implemented."; return tenUNKNOWN; } #endif - std::cerr << "doPayment: Delay transaction: No ripple paths could be satisfied." << std::endl; + Log(lsINFO) << "doPayment: Delay transaction: No ripple paths could be satisfied."; return terBAD_RIPPLE; } diff --git a/src/TransactionEngine.h b/src/TransactionEngine.h index 037ac19b87..f7f70b8122 100644 --- a/src/TransactionEngine.h +++ b/src/TransactionEngine.h @@ -10,43 +10,49 @@ enum TransactionEngineResult { + // Note: Numbers are currently unstable. Use tokens. + // tenCAN_NEVER_SUCCEED = <0 // Malformed: Fee claimed tenGEN_IN_USE = -300, - tenCREATEXNS, - tenEXPLICITXNS, - tenDST_NEEDED, - tenDST_IS_SRC, - tenBAD_GEN_AUTH, tenBAD_ADD_AUTH, + tenBAD_AMOUNT, tenBAD_CLAIM_ID, + tenBAD_GEN_AUTH, tenBAD_SET_ID, - tenDIRECT_XNS_ONLY, + tenCREATEXNS, + tenDST_IS_SRC, + tenDST_NEEDED, + tenEXPLICITXNS, + tenREDUNDANT, tenRIPPLE_EMPTY, // Invalid: Ledger won't allow. tenCLAIMED = -200, - tenCREATED, - tenMSG_SET, tenBAD_AUTH_MASTER, tenBAD_RIPPLE, + tenCREATED, + tenMSG_SET, terALREADY, // Other tenFAILED = -100, - tenUNKNOWN, tenINSUF_FEE_P, tenINVALID, + tenUNKNOWN, terSUCCESS = 0, // terFAILED_BUT_COULD_SUCCEED = >0 // Conflict with ledger database: Fee claimed // Might succeed if not conflict is not caused by transaction ordering. + terBAD_AUTH, + terBAD_RIPPLE, terBAD_SEQ, terCREATED, terDIR_FULL, + terFUNDS_SPENT, terINSUF_FEE_B, terINSUF_FEE_T, terNODE_NOT_FOUND, @@ -54,17 +60,15 @@ enum TransactionEngineResult terNODE_NO_ROOT, terNO_ACCOUNT, terNO_DST, + terNO_LINE_NO_ZERO, terNO_PATH, + terOVER_LIMIT, terPAST_LEDGER, terPAST_SEQ, terPRE_SEQ, - terUNFUNDED, - terNO_LINE_NO_ZERO, terSET_MISSING_DST, - terFUNDS_SPENT, terUNCLAIMED, - terBAD_AUTH, - terBAD_RIPPLE, + terUNFUNDED, }; bool transResultInfo(TransactionEngineResult terCode, std::string& strToken, std::string& strHuman); diff --git a/src/TransactionFormats.h b/src/TransactionFormats.h index d8c8fc38df..1f5b63d203 100644 --- a/src/TransactionFormats.h +++ b/src/TransactionFormats.h @@ -37,6 +37,7 @@ const int TransactionMaxLen = 1048576; // Transaction flags. const uint32 tfCreateAccount = 0x00010000; +const uint32 tfNoRippleDirect = 0x00020000; const uint32 tfUnsetEmailHash = 0x00010000; const uint32 tfUnsetWalletLocator = 0x00020000;