From e6511732c7bbaced3eb0aaf3350710b28d82b216 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Thu, 23 Aug 2012 22:31:14 -0700 Subject: [PATCH 01/10] Fix compiler warnings. --- src/Pathfinder.cpp | 31 +++++++++++++++---------------- src/Pathfinder.h | 4 ++-- src/TransactionEngine.cpp | 4 ++-- 3 files changed, 19 insertions(+), 20 deletions(-) diff --git a/src/Pathfinder.cpp b/src/Pathfinder.cpp index c1c5d86b30..a83771a57f 100644 --- a/src/Pathfinder.cpp +++ b/src/Pathfinder.cpp @@ -21,9 +21,9 @@ TODO: what is a good way to come up with multiple paths? OrderDB: - getXNSOffers(); - - // return list of all orderbooks that want XNS + getXNSOffers(); + + // return list of all orderbooks that want XNS // return list of all orderbooks that want IssuerID // return list of all orderbooks that want this issuerID and currencyID */ @@ -49,7 +49,7 @@ bool sortPathOptions(PathOption::pointer first, PathOption::pointer second) { 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); @@ -57,7 +57,7 @@ bool sortPathOptions(PathOption::pointer first, PathOption::pointer second) if(first->mPath.getElementCount()>second->mPath.getElementCount()) return(false); if(first->mMinWidthmMinWidth) return true; - + return false; } @@ -77,7 +77,7 @@ PathOption::PathOption(PathOption::pointer other) Pathfinder::Pathfinder(NewcoinAddress& srcAccountID, NewcoinAddress& dstAccountID, uint160& srcCurrencyID, STAmount dstAmount) : - mSrcAccountID(srcAccountID.getAccountID()) , mDstAccountID(dstAccountID.getAccountID()), mSrcCurrencyID(srcCurrencyID) , mDstAmount(dstAmount), mOrderBook(theApp->getMasterLedger().getCurrentLedger()) + mSrcAccountID(srcAccountID.getAccountID()), mDstAccountID(dstAccountID.getAccountID()), mDstAmount(dstAmount), mSrcCurrencyID(srcCurrencyID), mOrderBook(theApp->getMasterLedger().getCurrentLedger()) { mLedger=theApp->getMasterLedger().getCurrentLedger(); } @@ -99,9 +99,8 @@ bool Pathfinder::findPaths(int maxSearchSteps, int maxPay, STPathSet& retPathSet } if(checkComplete(retPathSet)) return(true); } - } - + return(false); } @@ -125,8 +124,8 @@ bool Pathfinder::checkComplete(STPathSet& retPathSet) // get all the options from this accountID // if source is XNS // every offer that wants XNS -// else -// every ripple line that starts with the source currency +// else +// every ripple line that starts with the source currency // every offer that we can take that wants the source currency void Pathfinder::addOptions(PathOption::pointer tail) @@ -150,7 +149,7 @@ void Pathfinder::addOptions(PathOption::pointer tail) 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)); @@ -161,7 +160,7 @@ void Pathfinder::addOptions(PathOption::pointer tail) pathOption->mCurrentAccount=line->getAccountIDPeer().getAccountID(); addPathOption(pathOption); - } + } } // every offer that wants the source currency @@ -184,7 +183,7 @@ void Pathfinder::addOptions(PathOption::pointer tail) void Pathfinder::addPathOption(PathOption::pointer pathOption) { - if(pathOption->mCurrencyID==mDstAmount.getCurrency()) + if(pathOption->mCurrencyID==mDstAmount.getCurrency()) { pathOption->mCorrectCurrency=true; @@ -192,11 +191,11 @@ void Pathfinder::addPathOption(PathOption::pointer pathOption) { // this path is complete mCompletePaths.push_back(pathOption); }else mBuildingPaths.push_back(pathOption); - }else + } + else { pathOption->mCorrectCurrency=false; mBuildingPaths.push_back(pathOption); } } - - +// vim:ts=4 diff --git a/src/Pathfinder.h b/src/Pathfinder.h index 5a7a4345a1..cc900e1e13 100644 --- a/src/Pathfinder.h +++ b/src/Pathfinder.h @@ -33,7 +33,6 @@ class Pathfinder OrderBookDB mOrderBook; Ledger::pointer mLedger; - std::list mBuildingPaths; std::list mCompletePaths; @@ -49,4 +48,5 @@ public: // returns false if there is no path. otherwise fills out retPath bool findPaths(int maxSearchSteps, int maxPay, STPathSet& retPathSet); -}; \ No newline at end of file +}; +// vim:ts=4 diff --git a/src/TransactionEngine.cpp b/src/TransactionEngine.cpp index e34387bae9..6db4f518b3 100644 --- a/src/TransactionEngine.cpp +++ b/src/TransactionEngine.cpp @@ -2618,8 +2618,8 @@ bool TransactionEngine::calcNodeAccountRev(unsigned int uIndex, PathState::point const uint160& uCurrencyID = pnCur.uCurrencyID; - const uint32 uQualityIn = uIndex ? rippleQualityIn(uCurAccountID, uPrvAccountID, uCurrencyID) : 1; - const uint32 uQualityOut = uIndex != uLast ? rippleQualityOut(uCurAccountID, uNxtAccountID, uCurrencyID) : 1; + const uint32 uQualityIn = uIndex ? rippleQualityIn(uCurAccountID, uPrvAccountID, uCurrencyID) : QUALITY_ONE; + const uint32 uQualityOut = uIndex != uLast ? rippleQualityOut(uCurAccountID, uNxtAccountID, uCurrencyID) : QUALITY_ONE; // For bPrvAccount const STAmount saPrvBalance = uIndex && bPrvAccount ? rippleBalance(uCurAccountID, uPrvAccountID, uCurrencyID) : STAmount(uCurrencyID); From db873ff9f52961526f07e4f78ca1743a4b624ba2 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Fri, 24 Aug 2012 09:32:58 -0700 Subject: [PATCH 02/10] Functions for owned nodes (nodes that have a single other node that owns them) and dual-owner nodes (nodes that have two other nodes that own them). Owned nodes would be things like nicknames. Dual-owner nodes would be things like ripple balances. --- src/SerializedLedger.cpp | 25 +++++++++++++++++++++++++ src/SerializedLedger.h | 5 +++++ 2 files changed, 30 insertions(+) diff --git a/src/SerializedLedger.cpp b/src/SerializedLedger.cpp index e79b19c1b7..5796952368 100644 --- a/src/SerializedLedger.cpp +++ b/src/SerializedLedger.cpp @@ -109,6 +109,31 @@ bool SerializedLedgerEntry::thread(const uint256& txID, uint32 ledgerSeq, uint25 return true; } +bool SerializedLedgerEntry::hasOneOwner() +{ + return (mType != ltACCOUNT_ROOT) && (getIFieldIndex(sfAccount) != -1); +} + +bool SerializedLedgerEntry::hasTwoOwners() +{ + return mType == ltRIPPLE_STATE; +} + +NewcoinAddress SerializedLedgerEntry::getOwner() +{ + return getIValueFieldAccount(sfAccount); +} + +NewcoinAddress SerializedLedgerEntry::getFirstOwner() +{ + return getIValueFieldAccount(sfLowID); +} + +NewcoinAddress SerializedLedgerEntry::getSecondOwner() +{ + return getIValueFieldAccount(sfHighID); +} + std::vector SerializedLedgerEntry::getOwners() { std::vector owners; diff --git a/src/SerializedLedger.h b/src/SerializedLedger.h index 5f66a765dc..21faba8c35 100644 --- a/src/SerializedLedger.h +++ b/src/SerializedLedger.h @@ -65,6 +65,11 @@ public: bool isThreadedType(); // is this a ledger entry that can be threaded bool isThreaded(); // is this ledger entry actually threaded + bool hasOneOwner(); // This node has one other node that owns it (like nickname) + bool hasTwoOwners(); // This node has two nodes that own it (like ripple balance) + NewcoinAddress getOwner(); + NewcoinAddress getFirstOwner(); + NewcoinAddress getSecondOwner(); uint256 getThreadedTransaction(); uint32 getThreadedLedger(); bool thread(const uint256& txID, uint32 ledgerSeq, uint256& prevTxID, uint32& prevLedgerID); From 82c3a49e26cd4253d5465bb942a5e8c57ea933a8 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Fri, 24 Aug 2012 09:35:26 -0700 Subject: [PATCH 03/10] Missing newlins. --- src/TransactionMeta.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/TransactionMeta.cpp b/src/TransactionMeta.cpp index b193afb48a..d6c80d9add 100644 --- a/src/TransactionMeta.cpp +++ b/src/TransactionMeta.cpp @@ -307,4 +307,4 @@ void TransactionMetaSet::deleteUnfunded(const uint256& nodeID, else node.addNode(new TMNEUnfunded(firstBalance, secondBalance)); } -#endif \ No newline at end of file +#endif From 4633aa019ccd25ef9a84fd6bea2d918fec2383a9 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Fri, 24 Aug 2012 09:35:35 -0700 Subject: [PATCH 04/10] Mid-level threading code. --- src/LedgerEntrySet.cpp | 94 +++++++++++++++++++++++++++++++++++++++++- src/LedgerEntrySet.h | 14 ++++++- 2 files changed, 105 insertions(+), 3 deletions(-) diff --git a/src/LedgerEntrySet.cpp b/src/LedgerEntrySet.cpp index ac110df3c3..06a718b52c 100644 --- a/src/LedgerEntrySet.cpp +++ b/src/LedgerEntrySet.cpp @@ -230,8 +230,70 @@ Json::Value LedgerEntrySet::getJson(int) const return ret; } -void LedgerEntrySet::addRawMeta(Serializer& s, Ledger::pointer origLedger) +SLE::pointer LedgerEntrySet::getForMod(const uint256& node, Ledger::pointer& ledger, + boost::unordered_map& newMods) { + boost::unordered_map::iterator it = mEntries.find(node); + if (it != mEntries.end()) + { + if (it->second.mAction == taaDELETE) + return SLE::pointer(); + if (it->second.mAction == taaCACHED) + it->second.mAction = taaMODIFY; + if (it->second.mSeq != mSeq) + { + it->second.mEntry = boost::make_shared(*it->second.mEntry); + it->second.mSeq = mSeq; + } + return it->second.mEntry; + } + + boost::unordered_map::iterator me = newMods.find(node); + if (me != newMods.end()) + return me->second; + + SLE::pointer ret = ledger->getSLE(node); + if (ret) + newMods.insert(std::make_pair(node, ret)); + return ret; + +} + +bool LedgerEntrySet::threadNode(SLE::pointer& node, const NewcoinAddress& threadTo, Ledger::pointer& ledger, + boost::unordered_map& newMods) +{ + SLE::pointer sle = getForMod(Ledger::getAccountRootIndex(threadTo.getAccountID()), ledger, newMods); + if ((!sle) || (sle->getIndex() == node->getIndex())) // do not self-thread + return false; + return threadNode(node, sle, ledger, newMods); +} + +bool LedgerEntrySet::threadNode(SLE::pointer& node, SLE::pointer& threadTo, Ledger::pointer& ledger, + boost::unordered_map& newMods) +{ + // WRITEME + return false; +} + +bool LedgerEntrySet::threadOwners(SLE::pointer& node, Ledger::pointer& ledger, + boost::unordered_map& newMods) +{ // thread new or modified node to owner or owners + if (node->hasOneOwner()) // thread to owner's account + return threadNode(node, node->getOwner(), ledger, newMods); + else if (node->hasTwoOwners()) // thread to owner's accounts + return + threadNode(node, node->getFirstOwner(), ledger, newMods) || + threadNode(node, node->getSecondOwner(), ledger, newMods); + else + return false; +} + +void LedgerEntrySet::calcRawMeta(Serializer& s, Ledger::pointer& origLedger) +{ // calculate the raw meta data and return it. This must be called before the set is committed + + // Entries modified only as a result of building the transaction metadata + boost::unordered_map newMod; + for (boost::unordered_map::const_iterator it = mEntries.begin(), end = mEntries.end(); it != end; ++it) { @@ -257,10 +319,38 @@ void LedgerEntrySet::addRawMeta(Serializer& s, Ledger::pointer origLedger) SLE::pointer origNode = origLedger->getSLE(it->first); SLE::pointer curNode = it->second.mEntry; - // FINISH + if (nType == TMNDeletedNode) + { + threadOwners(origNode, origLedger, newMod); + if (origNode->getType() == ltOFFER) + { // check for non-zero balances + // WRITEME + } + } + + if ((nType == TMNCreatedNode) || (nType == TMNModifiedNode)) + { + if (nType == TMNCreatedNode) // if created, thread to owner(s) + threadOwners(curNode, origLedger, newMod); + + if (curNode->isThreadedType()) // always thread to self + threadNode(curNode, curNode, origLedger, newMod); + + if (nType == TMNModifiedNode) + { + // analyze changes WRITEME + } + + } } } + + // add any new modified nodes to the modification set + for (boost::unordered_map::iterator it = newMod.begin(), end = newMod.end(); + it != end; ++it) + entryCache(it->second); + mSet.addRaw(s); } diff --git a/src/LedgerEntrySet.h b/src/LedgerEntrySet.h index cf4ee9b281..6d77b35928 100644 --- a/src/LedgerEntrySet.h +++ b/src/LedgerEntrySet.h @@ -38,6 +38,18 @@ protected: LedgerEntrySet(const boost::unordered_map &e, const TransactionMetaSet& s, int m) : mEntries(e), mSet(s), mSeq(m) { ; } + SLE::pointer getForMod(const uint256& node, Ledger::pointer& ledger, + boost::unordered_map& newMods); + + bool threadNode(SLE::pointer& node, const NewcoinAddress& threadTo, Ledger::pointer& ledger, + boost::unordered_map& newMods); + + bool threadNode(SLE::pointer& node, SLE::pointer& threadTo, Ledger::pointer& ledger, + boost::unordered_map& newMods); + + bool threadOwners(SLE::pointer& node, Ledger::pointer& ledger, + boost::unordered_map& newMods); + public: LedgerEntrySet() : mSeq(0) { ; } @@ -60,7 +72,7 @@ public: void entryModify(const SLE::pointer&); // This entry will be modified Json::Value getJson(int) const; - void addRawMeta(Serializer&, Ledger::pointer originalLedger); + void calcRawMeta(Serializer&, Ledger::pointer& originalLedger); // iterator functions bool isEmpty() const { return mEntries.empty(); } From 59cf54895395f0fd8682994ca7cf08395347285f Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Fri, 24 Aug 2012 20:17:46 -0700 Subject: [PATCH 05/10] Add issuer support to RPC send commend. --- src/RPCServer.cpp | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/src/RPCServer.cpp b/src/RPCServer.cpp index 8cd2a27f14..58f74143fc 100644 --- a/src/RPCServer.cpp +++ b/src/RPCServer.cpp @@ -45,7 +45,7 @@ Json::Value RPCServer::RPCError(int iError) { rpcBAD_SEED, "badSeed", "Disallowed seed." }, { rpcDST_ACT_MALFORMED, "dstActMalformed", "Destination account is malformed." }, { rpcDST_ACT_MISSING, "dstActMissing", "Destination account does not exists." }, - { rpcDST_AMT_MALFORMED, "dstAmtMalformed", "Destination amount/currency is malformed." }, + { rpcDST_AMT_MALFORMED, "dstAmtMalformed", "Destination amount/currency/issuer is malformed." }, { rpcFAIL_GEN_DECRPYT, "failGenDecrypt", "Failed to decrypt generator." }, { rpcGETS_ACT_MALFORMED, "getsActMalformed", "Gets account malformed." }, { rpcGETS_AMT_MALFORMED, "getsAmtMalformed", "Gets amount malformed." }, @@ -74,7 +74,7 @@ Json::Value RPCServer::RPCError(int iError) { rpcQUALITY_MALFORMED, "qualityMalformed", "Quality malformed." }, { rpcSRC_ACT_MALFORMED, "srcActMalformed", "Source account is malformed." }, { rpcSRC_ACT_MISSING, "srcActMissing", "Source account does not exist." }, - { rpcSRC_AMT_MALFORMED, "srcAmtMalformed", "Source amount/currency is malformed." }, + { rpcSRC_AMT_MALFORMED, "srcAmtMalformed", "Source amount/currency/issuer is malformed." }, { rpcSRC_UNCLAIMED, "srcUnclaimed", "Source account is not claimed." }, { rpcSUCCESS, "success", "Success." }, { rpcTXN_NOT_FOUND, "txnNotFound", "Transaction not found." }, @@ -1706,7 +1706,7 @@ Json::Value RPCServer::doRippleLinesGet(const Json::Value ¶ms) return ret; } -// send regular_seed paying_account account_id amount [currency] [send_max] [send_currency] +// send regular_seed paying_account account_id amount [currency] [issuer] [send_max] [send_currency] [send_issuer] Json::Value RPCServer::doSend(const Json::Value& params) { NewcoinAddress naSeed; @@ -1716,13 +1716,21 @@ Json::Value RPCServer::doSend(const Json::Value& params) STAmount saDstAmount; std::string sSrcCurrency; std::string sDstCurrency; + std::string sSrcIssuer; + std::string sDstIssuer; if (params.size() >= 5) sDstCurrency = params[4u].asString(); + if (params.size() >= 6) + sDstIssuer = params[5u].asString(); + if (params.size() >= 7) sSrcCurrency = params[6u].asString(); + if (params.size() >= 8) + sSrcIssuer = params[7u].asString(); + if (!naSeed.setSeedGeneric(params[0u].asString())) { return RPCError(rpcBAD_SEED); @@ -1735,11 +1743,11 @@ Json::Value RPCServer::doSend(const Json::Value& params) { return RPCError(rpcDST_ACT_MALFORMED); } - else if (!saDstAmount.setFullValue(params[3u].asString(), sDstCurrency)) + else if (!saDstAmount.setFullValue(params[3u].asString(), sDstCurrency, sDstIssuer)) { return RPCError(rpcDST_AMT_MALFORMED); } - else if (params.size() >= 6 && !saSrcAmountMax.setFullValue(params[5u].asString(), sSrcCurrency)) + else if (params.size() >= 7 && !saSrcAmountMax.setFullValue(params[5u].asString(), sSrcCurrency, sSrcIssuer)) { return RPCError(rpcSRC_AMT_MALFORMED); } @@ -1758,10 +1766,16 @@ Json::Value RPCServer::doSend(const Json::Value& params) Json::Value obj = authorize(uLedger, naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, saSrcBalance, saFee, asSrc, naVerifyGenerator); + // Log(lsINFO) << boost::str(boost::format("doSend: sSrcIssuer=%s sDstIssuer=%s saSrcAmountMax=%s saDstAmount=%s") + // % sSrcIssuer + // % sDstIssuer + // % saSrcAmountMax.getFullText() + // % saDstAmount.getFullText()); + if (!obj.empty()) return obj; - if (params.size() < 6) + if (params.size() < 7) saSrcAmountMax = saDstAmount; // Do a few simple checks. @@ -2554,7 +2568,7 @@ Json::Value RPCServer::doCommand(const std::string& command, Json::Value& params { "ripple", &RPCServer::doRipple, 8, -1, false, optCurrent|optClosed }, { "ripple_lines_get", &RPCServer::doRippleLinesGet, 1, 2, false, optCurrent }, { "ripple_line_set", &RPCServer::doRippleLineSet, 4, 7, false, optCurrent }, - { "send", &RPCServer::doSend, 3, 7, false, optCurrent }, + { "send", &RPCServer::doSend, 3, 9, false, optCurrent }, { "server_info", &RPCServer::doServerInfo, 0, 0, true }, { "stop", &RPCServer::doStop, 0, 0, true }, { "tx", &RPCServer::doTx, 1, 1, true }, From ba45778a08122a41e33a86e3749be3b310c55970 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Fri, 24 Aug 2012 20:18:07 -0700 Subject: [PATCH 06/10] Fixes for ripple quality in transaction engine. --- src/TransactionEngine.cpp | 65 ++++++++++++++------------------------- src/TransactionEngine.h | 5 +-- 2 files changed, 26 insertions(+), 44 deletions(-) diff --git a/src/TransactionEngine.cpp b/src/TransactionEngine.cpp index 6db4f518b3..88d7be6421 100644 --- a/src/TransactionEngine.cpp +++ b/src/TransactionEngine.cpp @@ -164,9 +164,9 @@ uint32 TransactionEngine::rippleTransferRate(const uint160& uIssuerID) } // XXX Might not need this, might store in nodes on calc reverse. -uint32 TransactionEngine::rippleQualityIn(const uint160& uToAccountID, const uint160& uFromAccountID, const uint160& uCurrencyID) +uint32 TransactionEngine::rippleQualityIn(const uint160& uToAccountID, const uint160& uFromAccountID, const uint160& uCurrencyID, const SOE_Field sfLow, const SOE_Field sfHigh) { - uint32 uQualityIn = QUALITY_ONE; + uint32 uQuality = QUALITY_ONE; SLE::pointer sleRippleState; if (uToAccountID == uFromAccountID) @@ -179,53 +179,28 @@ uint32 TransactionEngine::rippleQualityIn(const uint160& uToAccountID, const uin if (sleRippleState) { - SOE_Field sfField = uToAccountID < uFromAccountID ? sfLowQualityIn : sfHighQualityIn; + SOE_Field sfField = uToAccountID < uFromAccountID ? sfLow: sfHigh; - uQualityIn = sleRippleState->getIFieldPresent(sfField) + uQuality = sleRippleState->getIFieldPresent(sfField) ? sleRippleState->getIFieldU32(sfField) : QUALITY_ONE; - if (!uQualityIn) - uQualityIn = 1; + + if (!uQuality) + uQuality = 1; // Avoid divide by zero. } } - Log(lsINFO) << boost::str(boost::format("rippleQualityIn: uToAccountID=%s uFromAccountID=%s uCurrencyID=%s bLine=%d uQualityIn=%f") + Log(lsINFO) << boost::str(boost::format("rippleQuality: %s uToAccountID=%s uFromAccountID=%s uCurrencyID=%s bLine=%d uQuality=%f") + % (sfLow == sfLowQualityIn ? "in" : "out") % NewcoinAddress::createHumanAccountID(uToAccountID) % NewcoinAddress::createHumanAccountID(uFromAccountID) % STAmount::createHumanCurrency(uCurrencyID) % !!sleRippleState - % (uQualityIn/1000000000.0)); + % (uQuality/1000000000.0)); assert(uToAccountID == uFromAccountID || !!sleRippleState); - return uQualityIn; -} - -uint32 TransactionEngine::rippleQualityOut(const uint160& uToAccountID, const uint160& uFromAccountID, const uint160& uCurrencyID) -{ - uint32 uQualityOut = QUALITY_ONE; - - if (uToAccountID == uFromAccountID) - { - nothing(); - } - else - { - SLE::pointer sleRippleState = entryCache(ltRIPPLE_STATE, Ledger::getRippleStateIndex(uToAccountID, uFromAccountID, uCurrencyID)); - - if (sleRippleState) - { - uQualityOut = sleRippleState->getIFieldU32(uToAccountID < uFromAccountID ? sfLowQualityOut : sfHighQualityOut); - if (!uQualityOut) - uQualityOut = 1; - } - else - { - assert(false); - } - } - - return uQualityOut; + return uQuality; } // Return how much of uIssuerID's uCurrencyID IOUs that uAccountID holds. May be negative. @@ -2840,13 +2815,12 @@ bool TransactionEngine::calcNodeAccountRev(unsigned int uIndex, PathState::point else { // offer --> ACCOUNT --> account - // Note: offer is always deliver/redeeming as account is issuer. + // Note: offer is always delivering(redeeming) as account is issuer. Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev: offer --> ACCOUNT --> account")); // deliver -> redeem if (bRedeem // Allowed to redeem. - && saCurRedeemReq // Next wants us to redeem. - && saPrvBalance.isNegative()) // Previous has IOUs to redeem. + && saCurRedeemReq) // Next wants us to redeem. { // Rate : 1.0 : quality out calcNodeRipple(QUALITY_ONE, uQualityOut, saPrvDeliverReq, saCurRedeemReq, saPrvDeliverAct, saCurRedeemAct); @@ -2854,15 +2828,22 @@ bool TransactionEngine::calcNodeAccountRev(unsigned int uIndex, PathState::point // deliver -> issue. if (bIssue // Allowed to issue. - && saCurRedeemReq != saCurRedeemAct // Can only if issue if more can not be redeemed. - && saPrvBalance.isNegative() // Previous still has IOUs. + && saCurRedeemReq == saCurRedeemAct // Can only if issue if more can not be redeemed. && saCurIssueReq) // Need some issued. { // Rate : 1.0 : transfer_rate calcNodeRipple(QUALITY_ONE, rippleTransferRate(uCurAccountID), saPrvDeliverReq, saCurIssueReq, saPrvDeliverAct, saCurIssueAct); } - if (!saCurDeliverAct && !saCurIssueAct) + Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev: bRedeem=%d saCurRedeemReq=%s saCurIssueAct=%s bIssue=%d saCurIssueReq=%s saPrvDeliverAct=%s") + % bRedeem + % saCurRedeemReq.getFullText() + % saCurRedeemAct.getFullText() + % bIssue + % saCurIssueReq.getFullText() + % saPrvDeliverAct.getFullText()); + + if (!saPrvDeliverAct) { // Must want something. // terResult = tenBAD_AMOUNT; diff --git a/src/TransactionEngine.h b/src/TransactionEngine.h index fa93481e8d..e6ff7d6183 100644 --- a/src/TransactionEngine.h +++ b/src/TransactionEngine.h @@ -228,8 +228,9 @@ protected: uint32 rippleTransferRate(const uint160& uIssuerID); STAmount rippleBalance(const uint160& uToAccountID, const uint160& uFromAccountID, const uint160& uCurrencyID); STAmount rippleLimit(const uint160& uToAccountID, const uint160& uFromAccountID, const uint160& uCurrencyID); - uint32 rippleQualityIn(const uint160& uToAccountID, const uint160& uFromAccountID, const uint160& uCurrencyID); - uint32 rippleQualityOut(const uint160& uToAccountID, const uint160& uFromAccountID, const uint160& uCurrencyID); + uint32 rippleQualityIn(const uint160& uToAccountID, const uint160& uFromAccountID, const uint160& uCurrencyID, const SOE_Field sfLow=sfLowQualityIn, const SOE_Field sfHigh=sfHighQualityIn); + uint32 rippleQualityOut(const uint160& uToAccountID, const uint160& uFromAccountID, const uint160& uCurrencyID) + { return rippleQualityIn(uToAccountID, uFromAccountID, uCurrencyID, sfLowQualityOut, sfHighQualityOut); } STAmount rippleHolds(const uint160& uAccountID, const uint160& uCurrencyID, const uint160& uIssuerID); STAmount rippleTransferFee(const uint160& uSenderID, const uint160& uReceiverID, const uint160& uIssuerID, const STAmount& saAmount); From cf450106c4e7da969368a26b6cfe567159473024 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Sat, 25 Aug 2012 14:49:45 -0700 Subject: [PATCH 07/10] Require issuer when specifying currency when creating STAmount. --- src/Amount.cpp | 78 ++++++++++---------- src/SerializedTypes.h | 19 ++--- src/TransactionEngine.cpp | 148 ++++++++++++++++++++++---------------- src/TransactionEngine.h | 2 +- 4 files changed, 136 insertions(+), 111 deletions(-) diff --git a/src/Amount.cpp b/src/Amount.cpp index 1dfd549e47..b1588dc05a 100644 --- a/src/Amount.cpp +++ b/src/Amount.cpp @@ -651,10 +651,10 @@ STAmount operator-(const STAmount& v1, const STAmount& v2) return STAmount(v1.name, v1.mCurrency, -fv, ov1, true); } -STAmount STAmount::divide(const STAmount& num, const STAmount& den, const uint160& currencyOut) +STAmount STAmount::divide(const STAmount& num, const STAmount& den, const uint160& uCurrencyID, const uint160& uIssuerID) { if (den.isZero()) throw std::runtime_error("division by zero"); - if (num.isZero()) return STAmount(currencyOut); + if (num.isZero()) return STAmount(uCurrencyID, uIssuerID); uint64 numVal = num.mValue, denVal = den.mValue; int numOffset = num.mOffset, denOffset = den.mOffset; @@ -690,14 +690,14 @@ STAmount STAmount::divide(const STAmount& num, const STAmount& den, const uint16 assert(BN_num_bytes(&v) <= 64); if (num.mIsNegative != den.mIsNegative) - return -STAmount(currencyOut, v.getulong(), finOffset); - else return STAmount(currencyOut, v.getulong(), finOffset); + return -STAmount(uCurrencyID, uIssuerID, v.getulong(), finOffset); + else return STAmount(uCurrencyID, uIssuerID, v.getulong(), finOffset); } -STAmount STAmount::multiply(const STAmount& v1, const STAmount& v2, const uint160& currencyOut) +STAmount STAmount::multiply(const STAmount& v1, const STAmount& v2, const uint160& uCurrencyID, const uint160& uIssuerID) { if (v1.isZero() || v2.isZero()) - return STAmount(currencyOut); + return STAmount(uCurrencyID, uIssuerID); if (v1.mIsNative && v2.mIsNative) // FIXME: overflow return STAmount(v1.name, v1.getSNValue() * v2.getSNValue()); @@ -753,8 +753,8 @@ STAmount STAmount::multiply(const STAmount& v1, const STAmount& v2, const uint16 assert(BN_num_bytes(&v) <= 64); if (v1.mIsNegative != v2.mIsNegative) - return -STAmount(currencyOut, v.getulong(), offset1 + offset2 + 14); - else return STAmount(currencyOut, v.getulong(), offset1 + offset2 + 14); + return -STAmount(uCurrencyID, uIssuerID, v.getulong(), offset1 + offset2 + 14); + else return STAmount(uCurrencyID, uIssuerID, v.getulong(), offset1 + offset2 + 14); } // Convert an offer into an index amount so they sort by rate. @@ -769,7 +769,7 @@ uint64 STAmount::getRate(const STAmount& offerOut, const STAmount& offerIn) { if (offerOut.isZero()) throw std::runtime_error("Worthless offer"); - STAmount r = divide(offerIn, offerOut, uint160(1)); + STAmount r = divide(offerIn, offerOut, CURRENCY_ONE, ACCOUNT_ONE); assert((r.getExponent() >= -100) && (r.getExponent() <= 155)); @@ -778,12 +778,12 @@ uint64 STAmount::getRate(const STAmount& offerOut, const STAmount& offerIn) return (ret << (64 - 8)) | r.getMantissa(); } -STAmount STAmount::setRate(uint64 rate, const uint160& currencyOut) +STAmount STAmount::setRate(uint64 rate) { uint64 mantissa = rate & ~(255ull << (64 - 8)); int exponent = static_cast(rate >> (64 - 8)) - 100; - return STAmount(currencyOut, mantissa, exponent); + return STAmount(CURRENCY_ONE, ACCOUNT_ONE, mantissa, exponent); } // Taker gets all taker can pay for with saTakerFunds, limited by saOfferPays and saOfferFunds. @@ -814,7 +814,7 @@ bool STAmount::applyOffer( STAmount saOfferGetsAvailable = saOfferFunds == saOfferPays ? saOfferGets // Offer was fully funded, avoid shenanigans. - : divide(multiply(saTakerPays, saOfferPaysAvailable, uint160(1)), saTakerGets, saOfferGets.getCurrency()); + : divide(multiply(saTakerPays, saOfferPaysAvailable, CURRENCY_ONE, ACCOUNT_ONE), saTakerGets, saOfferGets.getCurrency(), saOfferGets.getIssuer()); if (saOfferGets == saOfferGetsAvailable && saTakerFunds >= saOfferGets) { @@ -836,7 +836,7 @@ bool STAmount::applyOffer( { // Taker only get's a portion of offer. saTakerPaid = saTakerFunds; // Taker paid all he had. - saTakerGot = divide(multiply(saTakerFunds, saOfferPaysAvailable, uint160(1)), saOfferGetsAvailable, saOfferPays.getCurrency()); + saTakerGot = divide(multiply(saTakerFunds, saOfferPaysAvailable, CURRENCY_ONE, ACCOUNT_ONE), saOfferGetsAvailable, saOfferPays.getCurrency(), saOfferPays.getIssuer()); Log(lsINFO) << "applyOffer: saTakerGot=" << saTakerGot.getFullText(); Log(lsINFO) << "applyOffer: saOfferPaysAvailable=" << saOfferPaysAvailable.getFullText(); @@ -848,7 +848,7 @@ bool STAmount::applyOffer( STAmount STAmount::getPay(const STAmount& offerOut, const STAmount& offerIn, const STAmount& needed) { // Someone wants to get (needed) out of the offer, how much should they pay in? if (offerOut.isZero()) - return STAmount(offerIn.getCurrency()); + return STAmount(offerIn.getCurrency(), offerIn.getIssuer()); if (needed >= offerOut) { @@ -856,7 +856,7 @@ STAmount STAmount::getPay(const STAmount& offerOut, const STAmount& offerIn, con return needed; } - STAmount ret = divide(multiply(needed, offerIn, uint160(1)), offerOut, offerIn.getCurrency()); + STAmount ret = divide(multiply(needed, offerIn, CURRENCY_ONE, ACCOUNT_ONE), offerOut, offerIn.getCurrency(), offerIn.getIssuer()); return (ret > offerIn) ? offerIn : ret; } @@ -1063,8 +1063,7 @@ BOOST_AUTO_TEST_CASE( NativeCurrency_test ) BOOST_AUTO_TEST_CASE( CustomCurrency_test ) { - uint160 currency(1); - STAmount zero(currency), one(currency, 1), hundred(currency, 100); + STAmount zero(CURRENCY_ONE, ACCOUNT_ONE), one(CURRENCY_ONE, ACCOUNT_ONE, 1), hundred(CURRENCY_ONE, ACCOUNT_ONE, 100); serdes(one).getRaw(); @@ -1131,33 +1130,33 @@ BOOST_AUTO_TEST_CASE( CustomCurrency_test ) if (!(hundred != zero)) BOOST_FAIL("STAmount fail"); if (!(hundred != one)) BOOST_FAIL("STAmount fail"); if ((hundred != hundred)) BOOST_FAIL("STAmount fail"); - if (STAmount(currency).getText() != "0") BOOST_FAIL("STAmount fail"); - if (STAmount(currency,31).getText() != "31") BOOST_FAIL("STAmount fail"); - if (STAmount(currency,31,1).getText() != "310") BOOST_FAIL("STAmount fail"); - if (STAmount(currency,31,-1).getText() != "3.1") BOOST_FAIL("STAmount fail"); - if (STAmount(currency,31,-2).getText() != "0.31") BOOST_FAIL("STAmount fail"); + if (STAmount(CURRENCY_ONE, ACCOUNT_ONE).getText() != "0") BOOST_FAIL("STAmount fail"); + if (STAmount(CURRENCY_ONE, ACCOUNT_ONE, 31).getText() != "31") BOOST_FAIL("STAmount fail"); + if (STAmount(CURRENCY_ONE, ACCOUNT_ONE, 31,1).getText() != "310") BOOST_FAIL("STAmount fail"); + if (STAmount(CURRENCY_ONE, ACCOUNT_ONE, 31,-1).getText() != "3.1") BOOST_FAIL("STAmount fail"); + if (STAmount(CURRENCY_ONE, ACCOUNT_ONE, 31,-2).getText() != "0.31") BOOST_FAIL("STAmount fail"); - if (STAmount::multiply(STAmount(currency, 20), STAmount(3), currency).getText() != "60") + if (STAmount::multiply(STAmount(CURRENCY_ONE, ACCOUNT_ONE, 20), STAmount(3), CURRENCY_ONE, ACCOUNT_ONE).getText() != "60") BOOST_FAIL("STAmount multiply fail"); - if (STAmount::multiply(STAmount(currency, 20), STAmount(3), uint160()).getText() != "60") + if (STAmount::multiply(STAmount(CURRENCY_ONE, ACCOUNT_ONE, 20), STAmount(3), uint160(), ACCOUNT_XNS).getText() != "60") BOOST_FAIL("STAmount multiply fail"); - if (STAmount::multiply(STAmount(20), STAmount(3), currency).getText() != "60") + if (STAmount::multiply(STAmount(20), STAmount(3), CURRENCY_ONE, ACCOUNT_ONE).getText() != "60") BOOST_FAIL("STAmount multiply fail"); - if (STAmount::multiply(STAmount(20), STAmount(3), uint160()).getText() != "60") + if (STAmount::multiply(STAmount(20), STAmount(3), uint160(), ACCOUNT_XNS).getText() != "60") BOOST_FAIL("STAmount multiply fail"); - if (STAmount::divide(STAmount(currency, 60) , STAmount(3), currency).getText() != "20") + if (STAmount::divide(STAmount(CURRENCY_ONE, ACCOUNT_ONE, 60), STAmount(3), CURRENCY_ONE, ACCOUNT_ONE).getText() != "20") BOOST_FAIL("STAmount divide fail"); - if (STAmount::divide(STAmount(currency, 60) , STAmount(3), uint160()).getText() != "20") + if (STAmount::divide(STAmount(CURRENCY_ONE, ACCOUNT_ONE, 60), STAmount(3), uint160(), ACCOUNT_XNS).getText() != "20") BOOST_FAIL("STAmount divide fail"); - if (STAmount::divide(STAmount(currency, 60) , STAmount(currency, 3), currency).getText() != "20") + if (STAmount::divide(STAmount(CURRENCY_ONE, ACCOUNT_ONE, 60), STAmount(CURRENCY_ONE, ACCOUNT_ONE, 3), CURRENCY_ONE, ACCOUNT_ONE).getText() != "20") BOOST_FAIL("STAmount divide fail"); - if (STAmount::divide(STAmount(currency, 60) , STAmount(currency, 3), uint160()).getText() != "20") + if (STAmount::divide(STAmount(CURRENCY_ONE, ACCOUNT_ONE, 60), STAmount(CURRENCY_ONE, ACCOUNT_ONE, 3), uint160(), ACCOUNT_XNS).getText() != "20") BOOST_FAIL("STAmount divide fail"); - STAmount a1(currency, 60), a2 (currency, 10, -1); - if (STAmount::divide(a2, a1, currency) != STAmount::setRate(STAmount::getRate(a1, a2), currency)) + STAmount a1(CURRENCY_ONE, ACCOUNT_ONE, 60), a2 (CURRENCY_ONE, ACCOUNT_ONE, 10, -1); + if (STAmount::divide(a2, a1, CURRENCY_ONE, ACCOUNT_ONE) != STAmount::setRate(STAmount::getRate(a1, a2))) BOOST_FAIL("STAmount setRate(getRate) fail"); - if (STAmount::divide(a1, a2, currency) != STAmount::setRate(STAmount::getRate(a2, a1), currency)) + if (STAmount::divide(a1, a2, CURRENCY_ONE, ACCOUNT_ONE) != STAmount::setRate(STAmount::getRate(a2, a1))) BOOST_FAIL("STAmount setRate(getRate) fail"); BOOST_TEST_MESSAGE("Amount CC Complete"); @@ -1168,22 +1167,21 @@ BOOST_AUTO_TEST_CASE( CurrencyMulDivTests ) // Test currency multiplication and division operations such as // convertToDisplayAmount, convertToInternalAmount, getRate, getClaimed, and getNeeded - uint160 c(1); if (STAmount::getRate(STAmount(1), STAmount(10)) != (((100ul-14)<<(64-8))|1000000000000000ul)) BOOST_FAIL("STAmount getRate fail"); if (STAmount::getRate(STAmount(10), STAmount(1)) != (((100ul-16)<<(64-8))|1000000000000000ul)) BOOST_FAIL("STAmount getRate fail"); - if (STAmount::getRate(STAmount(c, 1), STAmount(c, 10)) != (((100ul-14)<<(64-8))|1000000000000000ul)) + if (STAmount::getRate(STAmount(CURRENCY_ONE, ACCOUNT_ONE, 1), STAmount(CURRENCY_ONE, ACCOUNT_ONE, 10)) != (((100ul-14)<<(64-8))|1000000000000000ul)) BOOST_FAIL("STAmount getRate fail"); - if (STAmount::getRate(STAmount(c, 10), STAmount(c, 1)) != (((100ul-16)<<(64-8))|1000000000000000ul)) + if (STAmount::getRate(STAmount(CURRENCY_ONE, ACCOUNT_ONE, 10), STAmount(CURRENCY_ONE, ACCOUNT_ONE, 1)) != (((100ul-16)<<(64-8))|1000000000000000ul)) BOOST_FAIL("STAmount getRate fail"); - if (STAmount::getRate(STAmount(c, 1), STAmount(10)) != (((100ul-14)<<(64-8))|1000000000000000ul)) + if (STAmount::getRate(STAmount(CURRENCY_ONE, ACCOUNT_ONE, 1), STAmount(10)) != (((100ul-14)<<(64-8))|1000000000000000ul)) BOOST_FAIL("STAmount getRate fail"); - if (STAmount::getRate(STAmount(c, 10), STAmount(1)) != (((100ul-16)<<(64-8))|1000000000000000ul)) + if (STAmount::getRate(STAmount(CURRENCY_ONE, ACCOUNT_ONE, 10), STAmount(1)) != (((100ul-16)<<(64-8))|1000000000000000ul)) BOOST_FAIL("STAmount getRate fail"); - if (STAmount::getRate(STAmount(1), STAmount(c, 10)) != (((100ul-14)<<(64-8))|1000000000000000ul)) + if (STAmount::getRate(STAmount(1), STAmount(CURRENCY_ONE, ACCOUNT_ONE, 10)) != (((100ul-14)<<(64-8))|1000000000000000ul)) BOOST_FAIL("STAmount getRate fail"); - if (STAmount::getRate(STAmount(10), STAmount(c, 1)) != (((100ul-16)<<(64-8))|1000000000000000ul)) + if (STAmount::getRate(STAmount(10), STAmount(CURRENCY_ONE, ACCOUNT_ONE, 1)) != (((100ul-16)<<(64-8))|1000000000000000ul)) BOOST_FAIL("STAmount getRate fail"); } diff --git a/src/SerializedTypes.h b/src/SerializedTypes.h index 46439587a4..1017f758a3 100644 --- a/src/SerializedTypes.h +++ b/src/SerializedTypes.h @@ -261,10 +261,11 @@ public: : SerializedType(n), mValue(v), mOffset(0), mIsNative(true), mIsNegative(false) { ; } - STAmount(const uint160& uCurrency, uint64 uV=0, int iOff=0, bool bNegative=false) - : mCurrency(uCurrency), mValue(uV), mOffset(iOff), mIsNegative(bNegative) + STAmount(const uint160& uCurrencyID, const uint160& uIssuerID, uint64 uV=0, int iOff=0, bool bNegative=false) + : mCurrency(uCurrencyID), mIssuer(uIssuerID), mValue(uV), mOffset(iOff), mIsNegative(bNegative) { canonicalize(); } + // YYY This should probably require issuer too. STAmount(const char* n, const uint160& currency, uint64 v = 0, int off = 0, bool isNeg = false) : SerializedType(n), mCurrency(currency), mValue(v), mOffset(off), mIsNegative(isNeg) { canonicalize(); } @@ -274,14 +275,14 @@ public: static std::auto_ptr deserialize(SerializerIterator& sit, const char* name) { return std::auto_ptr(construct(sit, name)); } - static STAmount saFromRate(uint64 uV = 0) + static STAmount saFromRate(uint64 uRate = 0) { - return STAmount(CURRENCY_ONE, uV, -9, false); + return STAmount(CURRENCY_ONE, ACCOUNT_ONE, uRate, -9, false); } - static STAmount saFromSigned(const uint160& uCurrency, int64 iV=0, int iOff=0) + static STAmount saFromSigned(const uint160& uCurrencyID, const uint160& uIssuerID, int64 iV=0, int iOff=0) { - return STAmount(uCurrency, iV < 0 ? -iV : iV, iOff, iV < 0); + return STAmount(uCurrencyID, uIssuerID, iV < 0 ? -iV : iV, iOff, iV < 0); } int getLength() const { return mIsNative ? 8 : 28; } @@ -351,13 +352,13 @@ public: friend STAmount operator+(const STAmount& v1, const STAmount& v2); friend STAmount operator-(const STAmount& v1, const STAmount& v2); - static STAmount divide(const STAmount& v1, const STAmount& v2, const uint160& currencyOut); - static STAmount multiply(const STAmount& v1, const STAmount& v2, const uint160& currencyOut); + static STAmount divide(const STAmount& v1, const STAmount& v2, const uint160& uCurrencyID, const uint160& uIssuerID); + static STAmount multiply(const STAmount& v1, const STAmount& v2, const uint160& uCurrencyID, const uint160& uIssuerID); // Someone is offering X for Y, what is the rate? // Rate: smaller is better, the taker wants the most out: in/out static uint64 getRate(const STAmount& offerOut, const STAmount& offerIn); - static STAmount setRate(uint64 rate, const uint160& currencyOut); + static STAmount setRate(uint64 rate); // Someone is offering X for Y, I try to pay Z, how much do I get? // And what's left of the offer? And how much do I actually pay? diff --git a/src/TransactionEngine.cpp b/src/TransactionEngine.cpp index 88d7be6421..477ee82840 100644 --- a/src/TransactionEngine.cpp +++ b/src/TransactionEngine.cpp @@ -102,7 +102,9 @@ bool transResultInfo(TransactionEngineResult terCode, std::string& strToken, std return iIndex >= 0; } -STAmount TransactionEngine::rippleBalance(const uint160& uToAccountID, const uint160& uFromAccountID, const uint160& uCurrencyID) +// Returns amount owed by uToAccountID to uFromAccountID. +// <-- $owed/uCurrencyID/uToAccountID: positive: uFromAccountID holds IOUs., negative: uFromAccountID owes IOUs. +STAmount TransactionEngine::rippleOwed(const uint160& uToAccountID, const uint160& uFromAccountID, const uint160& uCurrencyID) { STAmount saBalance; SLE::pointer sleRippleState = entryCache(ltRIPPLE_STATE, Ledger::getRippleStateIndex(uToAccountID, uFromAccountID, uCurrencyID)); @@ -112,10 +114,11 @@ STAmount TransactionEngine::rippleBalance(const uint160& uToAccountID, const uin saBalance = sleRippleState->getIValueFieldAmount(sfBalance); if (uToAccountID < uFromAccountID) saBalance.negate(); + saBalance.setIssuer(uToAccountID); } else { - Log(lsINFO) << "rippleBalance: No credit line between " + Log(lsINFO) << "rippleOwed: No credit line between " << NewcoinAddress::createHumanAccountID(uFromAccountID) << " and " << NewcoinAddress::createHumanAccountID(uToAccountID) @@ -130,6 +133,8 @@ STAmount TransactionEngine::rippleBalance(const uint160& uToAccountID, const uin } +// Maximum amount of IOUs uToAccountID will hold from uFromAccountID. +// <-- $amount/uCurrencyID/uToAccountID. STAmount TransactionEngine::rippleLimit(const uint160& uToAccountID, const uint160& uFromAccountID, const uint160& uCurrencyID) { STAmount saLimit; @@ -139,6 +144,7 @@ STAmount TransactionEngine::rippleLimit(const uint160& uToAccountID, const uint1 if (sleRippleState) { saLimit = sleRippleState->getIValueFieldAmount(uToAccountID < uFromAccountID ? sfLowLimit : sfHighLimit); + saLimit.setIssuer(uToAccountID); } return saLimit; @@ -300,7 +306,7 @@ STAmount TransactionEngine::rippleTransferFee(const uint160& uSenderID, const ui { STAmount saTransitRate(CURRENCY_ONE, uTransitRate, -9); - saTransitFee = STAmount::multiply(saAmount, saTransitRate, saAmount.getCurrency()); + saTransitFee = STAmount::multiply(saAmount, saTransitRate, saAmount.getCurrency(), saAmount.getIssuer()); } } @@ -1583,9 +1589,9 @@ TransactionEngineResult TransactionEngine::doCreditSet(const SerializedTransacti Log(lsINFO) << "doCreditSet: Creating ripple line: " << sleRippleState->getIndex().ToString(); - sleRippleState->setIFieldAmount(sfBalance, STAmount(uCurrencyID)); // Zero balance in currency. + sleRippleState->setIFieldAmount(sfBalance, STAmount(uCurrencyID, ACCOUNT_ONE)); // Zero balance in currency. sleRippleState->setIFieldAmount(bFlipped ? sfHighLimit : sfLowLimit, saLimitAmount); - sleRippleState->setIFieldAmount(bFlipped ? sfLowLimit : sfHighLimit, STAmount(uCurrencyID)); + sleRippleState->setIFieldAmount(bFlipped ? sfLowLimit : sfHighLimit, STAmount(uCurrencyID, ACCOUNT_ONE)); sleRippleState->setIFieldAccount(bFlipped ? sfHighID : sfLowID, mTxnAccountID); sleRippleState->setIFieldAccount(bFlipped ? sfLowID : sfHighID, uDstAccountID); if (uQualityIn) @@ -1944,7 +1950,7 @@ bool TransactionEngine::calcNodeOfferRev( // - Drive on computing saCurDlvAct to derive saPrvDlvAct. // XXX Behave well, if entry type is wrong (someone beat us to using the hash) SLE::pointer sleDirectDir = entryCache(ltDIR_NODE, uDirectTip); - STAmount saOfrRate = STAmount::setRate(Ledger::getQuality(uDirectTip), uCurCurrencyID); // For correct ratio + STAmount saOfrRate = STAmount::setRate(Ledger::getQuality(uDirectTip)); // For correct ratio unsigned int uEntry = 0; uint256 uCurIndex; @@ -1987,13 +1993,13 @@ bool TransactionEngine::calcNodeOfferRev( STAmount saOutBase = MIN(saCurOfrOutReq, saCurDlvReq-saCurDlvAct); // Limit offer out by needed. STAmount saOutCost = MIN( bFee - ? STAmount::multiply(saOutBase, saFeeRate, uCurCurrencyID) + ? STAmount::multiply(saOutBase, saFeeRate, uCurCurrencyID, uCurIssuerID) : saOutBase, saCurOfrFunds); // Limit cost by fees & funds. STAmount saOutDlvAct = bFee - ? STAmount::divide(saOutCost, saFeeRate, uCurCurrencyID) + ? STAmount::divide(saOutCost, saFeeRate, uCurCurrencyID, uCurIssuerID) : saOutCost; // Out amount after fees. - STAmount saInDlvAct = STAmount::multiply(saOutDlvAct, saOfrRate, uPrvCurrencyID); // Compute input w/o fees required. + STAmount saInDlvAct = STAmount::multiply(saOutDlvAct, saOfrRate, uPrvCurrencyID, uCurIssuerID); // Compute input w/o fees required. saCurDlvAct += saOutDlvAct; // Portion of driver served. saPrvDlvAct += saInDlvAct; // Portion needed in previous. @@ -2044,13 +2050,14 @@ bool TransactionEngine::calcNodeOfferRev( saOutBase = MIN(saOutBase, saNxtOfrIn); // Limit offer out by supplying offer. STAmount saOutCost = MIN( bFee - ? STAmount::multiply(saOutBase, saFeeRate, uCurCurrencyID) + ? STAmount::multiply(saOutBase, saFeeRate, uCurCurrencyID, uCurIssuerID) : saOutBase, saCurOfrFunds); // Limit cost by fees & funds. STAmount saOutDlvAct = bFee - ? STAmount::divide(saOutCost, saFeeRate, uCurCurrencyID) + ? STAmount::divide(saOutCost, saFeeRate, uCurCurrencyID, uCurIssuerID) : saOutCost; // Out amount after fees. - STAmount saInDlvAct = STAmount::multiply(saOutDlvAct, saOfrRate, uPrvCurrencyID); // Compute input w/o fees required. + // Compute input w/o fees required. + STAmount saInDlvAct = STAmount::multiply(saOutDlvAct, saOfrRate, uPrvCurrencyID, uCurIssuerID); saCurDlvAct += saOutDlvAct; // Portion of driver served. saPrvDlvAct += saInDlvAct; // Portion needed in previous. @@ -2078,7 +2085,7 @@ bool TransactionEngine::calcNodeOfferRev( Log(lsINFO) << boost::str(boost::format("calcNodeOfferRev< uIndex=%d saPrvDlvReq=%s bSuccess=%d") % uIndex - % saPrvDlvReq.getText() + % saPrvDlvReq.getFullText() % bSuccess); return bSuccess; @@ -2134,7 +2141,7 @@ bool TransactionEngine::calcNodeOfferFwd( // Do a directory. // - Drive on computing saPrvDlvAct to derive saCurDlvAct. SLE::pointer sleDirectDir = entryCache(ltDIR_NODE, uDirectTip); - STAmount saOfrRate = STAmount::setRate(Ledger::getQuality(uDirectTip), uCurCurrencyID); // For correct ratio + STAmount saOfrRate = STAmount::setRate(Ledger::getQuality(uDirectTip)); // For correct ratio unsigned int uEntry = 0; uint256 uCurIndex; @@ -2158,17 +2165,18 @@ bool TransactionEngine::calcNodeOfferFwd( : saTransferRate; const bool bFee = saFeeRate != saOne; - const STAmount saOutPass = STAmount::divide(saCurOfrInMax, saOfrRate, uCurCurrencyID); + const STAmount saOutPass = STAmount::divide(saCurOfrInMax, saOfrRate, uCurCurrencyID, uCurIssuerID); const STAmount saOutBase = MIN(saCurOfrOutReq, saOutPass); // Limit offer out by needed. const STAmount saOutCost = MIN( bFee - ? STAmount::multiply(saOutBase, saFeeRate, uCurCurrencyID) + ? STAmount::multiply(saOutBase, saFeeRate, uCurCurrencyID, uCurIssuerID) : saOutBase, saCurOfrFunds); // Limit cost by fees & funds. const STAmount saOutDlvAct = bFee - ? STAmount::divide(saOutCost, saFeeRate, uCurCurrencyID) + ? STAmount::divide(saOutCost, saFeeRate, uCurCurrencyID, uCurIssuerID) : saOutCost; // Out amount after fees. - const STAmount saInDlvAct = STAmount::multiply(saOutDlvAct, saOfrRate, uCurCurrencyID); // Compute input w/o fees required. + // Compute input w/o fees required. + const STAmount saInDlvAct = STAmount::multiply(saOutDlvAct, saOfrRate, uCurCurrencyID, uCurIssuerID); saCurDlvAct += saOutDlvAct; // Portion of driver served. saPrvDlvAct += saInDlvAct; // Portion needed in previous. @@ -2216,18 +2224,18 @@ bool TransactionEngine::calcNodeOfferFwd( const bool bFee = saFeeRate != saOne; const STAmount saInBase = saCurOfrInMax-saCurOfrInAct; - const STAmount saOutPass = STAmount::divide(saInBase, saOfrRate, uCurCurrencyID); + const STAmount saOutPass = STAmount::divide(saInBase, saOfrRate, uCurCurrencyID, uCurIssuerID); STAmount saOutBase = MIN(saCurOfrOutReq, saOutPass); // Limit offer out by needed. saOutBase = MIN(saOutBase, saNxtOfrIn); // Limit offer out by supplying offer. const STAmount saOutCost = MIN( bFee - ? STAmount::multiply(saOutBase, saFeeRate, uCurCurrencyID) + ? STAmount::multiply(saOutBase, saFeeRate, uCurCurrencyID, uCurIssuerID) : saOutBase, saCurOfrFunds); // Limit cost by fees & funds. const STAmount saOutDlvAct = bFee - ? STAmount::divide(saOutCost, saFeeRate, uCurCurrencyID) + ? STAmount::divide(saOutCost, saFeeRate, uCurCurrencyID, uCurIssuerID) : saOutCost; // Out amount after fees. - const STAmount saInDlvAct = STAmount::multiply(saOutDlvAct, saOfrRate, uPrvCurrencyID); // Compute input w/o fees required. + const STAmount saInDlvAct = STAmount::multiply(saOutDlvAct, saOfrRate, uPrvCurrencyID, uCurIssuerID); // Compute input w/o fees required. saCurOfrInAct += saOutDlvAct; // Portion of driver served. saPrvDlvAct += saOutDlvAct; // Portion needed in previous. @@ -2538,8 +2546,11 @@ void TransactionEngine::calcNodeRipple( // Fee. Log(lsINFO) << boost::str(boost::format("calcNodeRipple: Fee")); - uint160 uCurrencyID = saCur.getCurrency(); - STAmount saCurIn = STAmount::divide(STAmount::multiply(saCur, uQualityOut, uCurrencyID), uQualityIn, uCurrencyID); + const uint160 uCurrencyID = saCur.getCurrency(); + const uint160 uCurIssuerID = saCur.getIssuer(); + const uint160 uPrvIssuerID = saPrv.getIssuer(); + + STAmount saCurIn = STAmount::divide(STAmount::multiply(saCur, uQualityOut, uCurrencyID, uCurIssuerID), uQualityIn, uCurrencyID, uCurIssuerID); Log(lsINFO) << boost::str(boost::format("calcNodeRipple: bPrvUnlimited=%d saPrv=%s saCurIn=%s") % bPrvUnlimited % saPrv.getFullText() % saCurIn.getFullText()); if (bPrvUnlimited || saCurIn <= saPrv) @@ -2552,8 +2563,7 @@ Log(lsINFO) << boost::str(boost::format("calcNodeRipple:3c: saCurReq=%s saPrvAct else { // A part of cur. All of prv. (cur as driver) - uint160 uCurrencyID = saPrv.getCurrency(); - STAmount saCurOut = STAmount::divide(STAmount::multiply(saPrv, uQualityIn, uCurrencyID), uQualityOut, uCurrencyID); + STAmount saCurOut = STAmount::divide(STAmount::multiply(saPrv, uQualityIn, uCurrencyID, uCurIssuerID), uQualityOut, uCurrencyID, uCurIssuerID); Log(lsINFO) << boost::str(boost::format("calcNodeRipple:4: saCurReq=%s") % saCurReq.getFullText()); saCurAct += saCurOut; @@ -2597,25 +2607,32 @@ bool TransactionEngine::calcNodeAccountRev(unsigned int uIndex, PathState::point const uint32 uQualityOut = uIndex != uLast ? rippleQualityOut(uCurAccountID, uNxtAccountID, uCurrencyID) : QUALITY_ONE; // For bPrvAccount - const STAmount saPrvBalance = uIndex && bPrvAccount ? rippleBalance(uCurAccountID, uPrvAccountID, uCurrencyID) : STAmount(uCurrencyID); - const STAmount saPrvLimit = uIndex && bPrvAccount ? rippleLimit(uCurAccountID, uPrvAccountID, uCurrencyID) : STAmount(uCurrencyID); + const STAmount saPrvOwed = uIndex && bPrvAccount // Previous account is owed. + ? rippleOwed(uCurAccountID, uPrvAccountID, uCurrencyID) + : STAmount(uCurrencyID, uCurAccountID); + const STAmount saPrvLimit = uIndex && bPrvAccount // Previous account may owe. + ? rippleLimit(uCurAccountID, uPrvAccountID, uCurrencyID) + : STAmount(uCurrencyID, uCurAccountID); - Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev> uIndex=%d/%d uPrvAccountID=%s uCurAccountID=%s uNxtAccountID=%s uCurrencyID=%s uQualityIn=%d uQualityOut=%d saPrvBalance=%s saPrvLimit=%s") + Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev> uIndex=%d/%d bPrvIssue=%d uPrvAccountID=%s uCurAccountID=%s uNxtAccountID=%s uCurrencyID=%s uQualityIn=%d uQualityOut=%d saPrvOwed=%s saPrvLimit=%s") % uIndex % uLast + % bPrvIssue % NewcoinAddress::createHumanAccountID(uPrvAccountID) % NewcoinAddress::createHumanAccountID(uCurAccountID) % NewcoinAddress::createHumanAccountID(uNxtAccountID) % STAmount::createHumanCurrency(uCurrencyID) % uQualityIn % uQualityOut - % saPrvBalance.getText() - % saPrvLimit.getText()); + % saPrvOwed.getFullText() + % saPrvLimit.getFullText()); - const STAmount saPrvRedeemReq = bPrvRedeem && saPrvBalance.isNegative() ? -saPrvBalance : STAmount(uCurrencyID, 0); + // Previous can redeem the owed IOUs it holds. + const STAmount saPrvRedeemReq = bPrvRedeem && saPrvOwed.isPositive() ? saPrvOwed : STAmount(uCurrencyID, 0); STAmount& saPrvRedeemAct = pnPrv.saRevRedeem; - const STAmount saPrvIssueReq = bPrvIssue ? saPrvLimit - saPrvBalance : STAmount(uCurrencyID); + // Previous can issue up to limit minus whatever portion of limit already used (not including redeemable amount). + const STAmount saPrvIssueReq = bPrvIssue && saPrvOwed.isNegative() ? saPrvLimit+saPrvOwed : saPrvLimit; STAmount& saPrvIssueAct = pnPrv.saRevIssue; // For !bPrvAccount @@ -2624,27 +2641,25 @@ bool TransactionEngine::calcNodeAccountRev(unsigned int uIndex, PathState::point // For bNxtAccount const STAmount& saCurRedeemReq = pnCur.saRevRedeem; - STAmount saCurRedeemAct(saCurRedeemReq.getCurrency()); + STAmount saCurRedeemAct(saCurRedeemReq.getCurrency(), saCurRedeemReq.getIssuer()); const STAmount& saCurIssueReq = pnCur.saRevIssue; - STAmount saCurIssueAct(saCurIssueReq.getCurrency()); // Track progress. + STAmount saCurIssueAct(saCurIssueReq.getCurrency(), saCurIssueReq.getIssuer()); // Track progress. // For !bNxtAccount const STAmount& saCurDeliverReq = pnCur.saRevDeliver; - STAmount saCurDeliverAct(saCurDeliverReq.getCurrency()); + STAmount saCurDeliverAct(saCurDeliverReq.getCurrency(), saCurDeliverReq.getIssuer()); - // For uIndex == uLast - const STAmount& saCurWantedReq = pspCur->saOutReq; // XXX Credit limits? - // STAmount saPrvDeliverReq = saPrvBalance.isPositive() ? saPrvLimit - saPrvBalance : saPrvLimit; - STAmount saCurWantedAct(saCurWantedReq.getCurrency()); + // For uIndex == uLast, over all deliverable. + const STAmount& saCurWantedReq = bPrvAccount + ? MIN(pspCur->saOutReq, saPrvLimit+saPrvOwed) // If previous is an account, limit. + : pspCur->saOutReq; // Previous is an offer, no limit: redeem own IOUs. + STAmount saCurWantedAct(saCurWantedReq.getCurrency(), saCurWantedReq.getIssuer()); - Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev: saPrvRedeemReq=%s/%s saPrvIssueReq=%s/%s saCurWantedReq=%s/%s") - % saPrvRedeemReq.getText() - % saPrvRedeemReq.getHumanCurrency() - % saPrvIssueReq.getText() - % saPrvIssueReq.getHumanCurrency() - % saCurWantedReq.getText() - % saCurWantedReq.getHumanCurrency()); + Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev: saPrvRedeemReq=%s saPrvIssueReq=%s saCurWantedReq=%s") + % saPrvRedeemReq.getFullText() + % saPrvIssueReq.getFullText() + % saCurWantedReq.getFullText()); Log(lsINFO) << pspCur->getJson(); @@ -2698,7 +2713,7 @@ bool TransactionEngine::calcNodeAccountRev(unsigned int uIndex, PathState::point if (bPrvRedeem && bRedeem // Allowed to redeem. && saCurRedeemReq // Next wants us to redeem. - && saPrvBalance.isNegative()) // Previous has IOUs to redeem. + && saPrvOwed) // Previous has IOUs to redeem. { // Rate : 1.0 : quality out Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev: Rate : 1.0 : quality out")); @@ -2710,7 +2725,7 @@ bool TransactionEngine::calcNodeAccountRev(unsigned int uIndex, PathState::point if (bPrvRedeem && bIssue // Allowed to issue. && saCurRedeemReq != saCurRedeemAct // Can only if issue if more can not be redeemed. - && saPrvBalance.isNegative() // Previous still has IOUs. + && saPrvOwed // Previous still has IOUs. && saCurIssueReq) // Need some issued. { // Rate : 1.0 : transfer_rate @@ -2723,7 +2738,7 @@ bool TransactionEngine::calcNodeAccountRev(unsigned int uIndex, PathState::point if (bPrvIssue && bRedeem // Allowed to redeem. && saCurRedeemReq != saCurRedeemAct // Can only redeem if more to be redeemed. - && !saPrvBalance.isNegative()) // Previous has no IOUs. + && !saPrvOwed.isPositive()) // Previous has no IOUs. { // Rate: quality in : quality out Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev: Rate: quality in : quality out")); @@ -2735,7 +2750,7 @@ bool TransactionEngine::calcNodeAccountRev(unsigned int uIndex, PathState::point if (bPrvIssue && bIssue // Allowed to issue. && saCurRedeemReq == saCurRedeemAct // Can only if issue if more can not be redeemed. - && !saPrvBalance.isNegative() // Previous has no IOUs. + && !saPrvOwed.isPositive() // Previous has no IOUs. && saCurIssueReq != saCurIssueAct) // Need some issued. { // Rate: quality in : 1.0 @@ -2750,14 +2765,15 @@ bool TransactionEngine::calcNodeAccountRev(unsigned int uIndex, PathState::point // terResult = tenBAD_AMOUNT; bSuccess = false; } - Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev: ^|account --> ACCOUNT --> account : bPrvRedeem=%d bPrvIssue=%d bRedeem=%d bIssue=%d saCurRedeemReq=%s saCurIssueReq=%s saPrvBalance=%s saCurRedeemAct=%s saCurIssueAct=%s") + + Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev: ^|account --> ACCOUNT --> account : bPrvRedeem=%d bPrvIssue=%d bRedeem=%d bIssue=%d saCurRedeemReq=%s saCurIssueReq=%s saPrvOwed=%s saCurRedeemAct=%s saCurIssueAct=%s") % bPrvRedeem % bPrvIssue % bRedeem % bIssue % saCurRedeemReq.getFullText() % saCurIssueReq.getFullText() - % saPrvBalance.getFullText() + % saPrvOwed.getFullText() % saCurRedeemAct.getFullText() % saCurIssueAct.getFullText()); } @@ -2771,7 +2787,7 @@ bool TransactionEngine::calcNodeAccountRev(unsigned int uIndex, PathState::point // redeem -> deliver/issue. if (bPrvRedeem && bIssue // Allowed to issue. - && saPrvBalance.isNegative() // Previous redeeming: Previous still has IOUs. + && saPrvOwed.isPositive() // Previous redeeming: Previous still has IOUs. && saCurDeliverReq) // Need some issued. { // Rate : 1.0 : transfer_rate @@ -2781,7 +2797,8 @@ bool TransactionEngine::calcNodeAccountRev(unsigned int uIndex, PathState::point // issue -> deliver/issue if (bPrvIssue && bIssue // Allowed to issue. - && !saPrvBalance.isNegative() // Previous issuing: Previous has no IOUs. + && (!saPrvOwed.isPositive() // Previous issuing: Never had IOUs. + || saPrvOwed == saPrvRedeemAct) // Previous issuing: Previous has no IOUs left after redeeming. && saCurDeliverReq != saCurDeliverAct) // Need some issued. { // Rate: quality in : 1.0 @@ -2794,6 +2811,15 @@ bool TransactionEngine::calcNodeAccountRev(unsigned int uIndex, PathState::point // terResult = tenBAD_AMOUNT; bSuccess = false; } + + Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev: bPrvRedeem=%d bPrvIssue=%d bRedeem=%d bIssue=%d saCurDeliverReq=%s saCurDeliverAct=%s saPrvOwed=%s") + % bPrvRedeem + % bPrvIssue + % bRedeem + % bIssue + % saCurDeliverReq.getFullText() + % saCurDeliverAct.getFullText() + % saPrvOwed.getFullText()); } else if (!bPrvAccount && bNxtAccount) { @@ -2906,14 +2932,14 @@ bool TransactionEngine::calcNodeAccountFwd(unsigned int uIndex, PathState::point // For bNxtAccount const STAmount& saPrvRedeemReq = pnPrv.saFwdRedeem; - STAmount saPrvRedeemAct(saPrvRedeemReq.getCurrency()); + STAmount saPrvRedeemAct(saPrvRedeemReq.getCurrency(), saPrvRedeemReq.getIssuer()); const STAmount& saPrvIssueReq = pnPrv.saFwdIssue; - STAmount saPrvIssueAct(saPrvIssueReq.getCurrency()); + STAmount saPrvIssueAct(saPrvIssueReq.getCurrency(), saPrvIssueReq.getIssuer()); // For !bPrvAccount const STAmount& saPrvDeliverReq = pnPrv.saRevDeliver; - STAmount saPrvDeliverAct(saPrvDeliverReq.getCurrency()); + STAmount saPrvDeliverAct(saPrvDeliverReq.getCurrency(), saPrvDeliverReq.getIssuer()); // For bNxtAccount const STAmount& saCurRedeemReq = pnCur.saRevRedeem; @@ -3003,7 +3029,7 @@ bool TransactionEngine::calcNodeAccountFwd(unsigned int uIndex, PathState::point STAmount saIssueCrd = uQualityIn >= QUALITY_ONE ? saPrvIssueReq // No fee. - : STAmount::multiply(saPrvIssueReq, uQualityIn, uCurrencyID); // Fee. + : STAmount::multiply(saPrvIssueReq, uQualityIn, uCurrencyID, saPrvIssueReq.getIssuer()); // Fee. // Amount to credit. saCurReceive = saPrvRedeemReq+saIssueCrd; @@ -3259,8 +3285,8 @@ bool PathState::pushNode(int iType, uint160 uAccountID, uint160 uCurrencyID, uin pnCur.uAccountID = uAccountID; pnCur.uCurrencyID = bCurrency ? uCurrencyID : pnPrv.uCurrencyID; pnCur.uIssuerID = bIssuer ? uIssuerID : uAccountID; - pnCur.saRevRedeem = STAmount(uCurrencyID); - pnCur.saRevIssue = STAmount(uCurrencyID); + pnCur.saRevRedeem = STAmount(uCurrencyID, uAccountID); + pnCur.saRevIssue = STAmount(uCurrencyID, uAccountID); if (!bFirst) { diff --git a/src/TransactionEngine.h b/src/TransactionEngine.h index e6ff7d6183..6204650fe4 100644 --- a/src/TransactionEngine.h +++ b/src/TransactionEngine.h @@ -226,7 +226,7 @@ protected: void entryModify(SLE::pointer sleEntry); uint32 rippleTransferRate(const uint160& uIssuerID); - STAmount rippleBalance(const uint160& uToAccountID, const uint160& uFromAccountID, const uint160& uCurrencyID); + STAmount rippleOwed(const uint160& uToAccountID, const uint160& uFromAccountID, const uint160& uCurrencyID); STAmount rippleLimit(const uint160& uToAccountID, const uint160& uFromAccountID, const uint160& uCurrencyID); uint32 rippleQualityIn(const uint160& uToAccountID, const uint160& uFromAccountID, const uint160& uCurrencyID, const SOE_Field sfLow=sfLowQualityIn, const SOE_Field sfHigh=sfHighQualityIn); uint32 rippleQualityOut(const uint160& uToAccountID, const uint160& uFromAccountID, const uint160& uCurrencyID) From 3fd5e10390538e40492f7b2cc4e43cabf0b9967d Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Sat, 25 Aug 2012 18:03:05 -0700 Subject: [PATCH 08/10] More ripple engine fixes. --- src/TransactionEngine.cpp | 82 ++++++++++++++++++++++----------------- 1 file changed, 47 insertions(+), 35 deletions(-) diff --git a/src/TransactionEngine.cpp b/src/TransactionEngine.cpp index 477ee82840..3a40198743 100644 --- a/src/TransactionEngine.cpp +++ b/src/TransactionEngine.cpp @@ -1886,12 +1886,11 @@ void TransactionEngine::calcOfferBridgeNext( // <-- bSuccess: false= no transfer // XXX Make sure missing ripple path is addressed cleanly. bool TransactionEngine::calcNodeOfferRev( - unsigned int uIndex, // 0 < uIndex < uLast-1 + unsigned int uIndex, // 0 < uIndex < uLast PathState::pointer pspCur, - bool bMultiQuality - ) + bool bMultiQuality) { - bool bSuccess = false; + bool bSuccess = false; paymentNode& pnPrv = pspCur->vpnNodes[uIndex-1]; paymentNode& pnCur = pspCur->vpnNodes[uIndex]; @@ -2092,7 +2091,7 @@ bool TransactionEngine::calcNodeOfferRev( } bool TransactionEngine::calcNodeOfferFwd( - unsigned int uIndex, // 0 < uIndex < uLast-1 + unsigned int uIndex, // 0 < uIndex < uLast PathState::pointer pspCur, bool bMultiQuality ) @@ -2583,8 +2582,8 @@ Log(lsINFO) << boost::str(boost::format("calcNodeRipple:4: saCurReq=%s") % saCur // Calculate saPrvRedeemReq, saPrvIssueReq, saPrvDeliver; bool TransactionEngine::calcNodeAccountRev(unsigned int uIndex, PathState::pointer pspCur, bool bMultiQuality) { - bool bSuccess = true; - const unsigned int uLast = pspCur->vpnNodes.size() - 1; + bool bSuccess = true; + const unsigned int uLast = pspCur->vpnNodes.size() - 1; paymentNode& pnPrv = pspCur->vpnNodes[uIndex ? uIndex-1 : 0]; paymentNode& pnCur = pspCur->vpnNodes[uIndex]; @@ -2636,7 +2635,7 @@ bool TransactionEngine::calcNodeAccountRev(unsigned int uIndex, PathState::point STAmount& saPrvIssueAct = pnPrv.saRevIssue; // For !bPrvAccount - const STAmount saPrvDeliverReq = STAmount::saFromSigned(uCurrencyID, -1); // Unlimited. + const STAmount saPrvDeliverReq = STAmount::saFromSigned(uCurrencyID, uCurAccountID, -1); // Unlimited. STAmount& saPrvDeliverAct = pnPrv.saRevDeliver; // For bNxtAccount @@ -2650,16 +2649,9 @@ bool TransactionEngine::calcNodeAccountRev(unsigned int uIndex, PathState::point const STAmount& saCurDeliverReq = pnCur.saRevDeliver; STAmount saCurDeliverAct(saCurDeliverReq.getCurrency(), saCurDeliverReq.getIssuer()); - // For uIndex == uLast, over all deliverable. - const STAmount& saCurWantedReq = bPrvAccount - ? MIN(pspCur->saOutReq, saPrvLimit+saPrvOwed) // If previous is an account, limit. - : pspCur->saOutReq; // Previous is an offer, no limit: redeem own IOUs. - STAmount saCurWantedAct(saCurWantedReq.getCurrency(), saCurWantedReq.getIssuer()); - - Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev: saPrvRedeemReq=%s saPrvIssueReq=%s saCurWantedReq=%s") + Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev: saPrvRedeemReq=%s saPrvIssueReq=%s") % saPrvRedeemReq.getFullText() - % saPrvIssueReq.getFullText() - % saCurWantedReq.getFullText()); + % saPrvIssueReq.getFullText()); Log(lsINFO) << pspCur->getJson(); @@ -2674,7 +2666,14 @@ bool TransactionEngine::calcNodeAccountRev(unsigned int uIndex, PathState::point else if (uIndex == uLast) { // account --> ACCOUNT --> $ - Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev: account --> ACCOUNT --> $")); + // Overall deliverable. + const STAmount& saCurWantedReq = bPrvAccount + ? MIN(pspCur->saOutReq, saPrvLimit+saPrvOwed) // If previous is an account, limit. + : pspCur->saOutReq; // Previous is an offer, no limit: redeem own IOUs. + STAmount saCurWantedAct(saCurWantedReq.getCurrency(), saCurWantedReq.getIssuer()); + + Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev: account --> ACCOUNT --> $ : saCurWantedReq=%s") + % saCurWantedReq.getFullText()); // Calculate redeem if (bRedeem @@ -2826,7 +2825,13 @@ bool TransactionEngine::calcNodeAccountRev(unsigned int uIndex, PathState::point if (uIndex == uLast) { // offer --> ACCOUNT --> $ - Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev: offer --> ACCOUNT --> $")); + const STAmount& saCurWantedReq = bPrvAccount + ? MIN(pspCur->saOutReq, saPrvLimit+saPrvOwed) // If previous is an account, limit. + : pspCur->saOutReq; // Previous is an offer, no limit: redeem own IOUs. + STAmount saCurWantedAct(saCurWantedReq.getCurrency(), saCurWantedReq.getIssuer()); + + Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev: offer --> ACCOUNT --> $ : saCurWantedReq=%s") + % saCurWantedReq.getFullText()); // Rate: quality in : 1.0 calcNodeRipple(uQualityIn, QUALITY_ONE, saPrvDeliverReq, saCurWantedReq, saPrvDeliverAct, saCurWantedAct); @@ -2907,9 +2912,12 @@ bool TransactionEngine::calcNodeAccountRev(unsigned int uIndex, PathState::point // The current node: specify what to push through to next. // - Output to next node minus fees. // Perform balance adjustment with previous. -bool TransactionEngine::calcNodeAccountFwd(unsigned int uIndex, PathState::pointer pspCur, bool bMultiQuality) +bool TransactionEngine::calcNodeAccountFwd( + unsigned int uIndex, // 0 <= uIndex <= uLast + PathState::pointer pspCur, + bool bMultiQuality) { - bool bSuccess = true; + bool bSuccess = true; const unsigned int uLast = pspCur->vpnNodes.size() - 1; paymentNode& pnPrv = pspCur->vpnNodes[uIndex ? uIndex-1 : 0]; @@ -2921,14 +2929,14 @@ bool TransactionEngine::calcNodeAccountFwd(unsigned int uIndex, PathState::point const bool bPrvAccount = !!(pnPrv.uFlags & STPathElement::typeAccount); const bool bNxtAccount = !!(pnNxt.uFlags & STPathElement::typeAccount); - const uint160& uPrvAccountID = pnPrv.uAccountID; const uint160& uCurAccountID = pnCur.uAccountID; + const uint160& uPrvAccountID = bPrvAccount ? pnPrv.uAccountID : uCurAccountID; const uint160& uNxtAccountID = bNxtAccount ? pnNxt.uAccountID : uCurAccountID; // Offers are always issue. const uint160& uCurrencyID = pnCur.uCurrencyID; - uint32 uQualityIn = rippleQualityIn(uCurAccountID, uPrvAccountID, uCurrencyID); - uint32 uQualityOut = rippleQualityOut(uCurAccountID, uNxtAccountID, uCurrencyID); + uint32 uQualityIn = uIndex ? rippleQualityIn(uCurAccountID, uPrvAccountID, uCurrencyID) : QUALITY_ONE; + uint32 uQualityOut = uIndex == uLast ? rippleQualityOut(uCurAccountID, uNxtAccountID, uCurrencyID) : QUALITY_ONE; // For bNxtAccount const STAmount& saPrvRedeemReq = pnPrv.saFwdRedeem; @@ -2952,17 +2960,17 @@ bool TransactionEngine::calcNodeAccountFwd(unsigned int uIndex, PathState::point const STAmount& saCurDeliverReq = pnCur.saRevDeliver; STAmount& saCurDeliverAct = pnCur.saFwdDeliver; - STAmount& saCurReceive = pspCur->saOutAct; - - Log(lsINFO) << boost::str(boost::format("calcNodeAccountFwd> uIndex=%d/%d saCurRedeemReq=%s/%s saCurIssueReq=%s/%s saCurDeliverReq=%s/%s") + Log(lsINFO) << boost::str(boost::format("calcNodeAccountFwd> uIndex=%d/%d bRedeem=%d bIssue=%d saPrvRedeemReq=%s saPrvIssueReq=%s saPrvDeliverReq=%s saCurRedeemReq=%s saCurIssueReq=%s saCurDeliverReq=%s") % uIndex % uLast - % saCurRedeemReq.getText() - % saCurRedeemReq.getHumanCurrency() - % saCurIssueReq.getText() - % saCurIssueReq.getHumanCurrency() - % saCurDeliverReq.getText() - % saCurDeliverReq.getHumanCurrency()); + % bRedeem + % bIssue + % saPrvRedeemReq.getFullText() + % saPrvIssueReq.getFullText() + % saPrvDeliverReq.getFullText() + % saCurRedeemReq.getFullText() + % saCurIssueReq.getFullText() + % saCurDeliverReq.getFullText()); // Ripple through account. @@ -3027,7 +3035,9 @@ bool TransactionEngine::calcNodeAccountFwd(unsigned int uIndex, PathState::point // Last node. Accept all funds. Calculate amount actually to credit. - STAmount saIssueCrd = uQualityIn >= QUALITY_ONE + STAmount& saCurReceive = pspCur->saOutAct; + + STAmount saIssueCrd = uQualityIn >= QUALITY_ONE ? saPrvIssueReq // No fee. : STAmount::multiply(saPrvIssueReq, uQualityIn, uCurrencyID, saPrvIssueReq.getIssuer()); // Fee. @@ -3117,6 +3127,8 @@ bool TransactionEngine::calcNodeAccountFwd(unsigned int uIndex, PathState::point // offer --> ACCOUNT --> $ Log(lsINFO) << boost::str(boost::format("calcNodeAccountFwd: offer --> ACCOUNT --> $")); + STAmount& saCurReceive = pspCur->saOutAct; + // Amount to credit. saCurReceive = saPrvDeliverAct; @@ -3143,7 +3155,7 @@ bool TransactionEngine::calcNodeAccountFwd(unsigned int uIndex, PathState::point && saCurIssueReq) // Current wants issue. { // Rate : 1.0 : transfer_rate - calcNodeRipple(QUALITY_ONE, rippleTransferRate(uCurAccountID), saPrvRedeemReq, saCurIssueReq, saPrvRedeemAct, saCurIssueAct); + calcNodeRipple(QUALITY_ONE, rippleTransferRate(uCurAccountID), saPrvDeliverReq, saCurIssueReq, saPrvDeliverAct, saCurIssueAct); } // No income balance adjustments necessary. The paying side inside the offer paid and the next link will receive. From bb7f692a762475159db9c85a842b25e56a6a1d20 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Sun, 26 Aug 2012 20:38:35 -0700 Subject: [PATCH 09/10] Rework transaction engine result codes. --- src/NetworkOPs.cpp | 8 +- src/TransactionEngine.cpp | 460 ++++++++++++++++---------------------- src/TransactionEngine.h | 124 +++++----- 3 files changed, 262 insertions(+), 330 deletions(-) diff --git a/src/NetworkOPs.cpp b/src/NetworkOPs.cpp index adc8a3c7b9..40cd4cc856 100644 --- a/src/NetworkOPs.cpp +++ b/src/NetworkOPs.cpp @@ -85,7 +85,7 @@ Transaction::pointer NetworkOPs::processTransaction(Transaction::pointer trans, } TransactionEngineResult r = mLedgerMaster->doTransaction(*trans->getSTransaction(), tgtLedger, tepNONE); - if (r == tenFAILED) throw Fault(IO_ERROR); + if (r == tefFAILURE) throw Fault(IO_ERROR); if (r == terPRE_SEQ) { // transaction should be held @@ -95,14 +95,14 @@ Transaction::pointer NetworkOPs::processTransaction(Transaction::pointer trans, mLedgerMaster->addHeldTransaction(trans); return trans; } - if ((r == terPAST_SEQ) || (r == terPAST_LEDGER)) + if ((r == tefPAST_SEQ)) { // duplicate or conflict Log(lsINFO) << "Transaction is obsolete"; trans->setStatus(OBSOLETE); return trans; } - if (r == terSUCCESS) + if (r == tesSUCCESS) { Log(lsINFO) << "Transaction is now included"; trans->setStatus(INCLUDED); @@ -875,7 +875,7 @@ void NetworkOPs::pubLedger(const Ledger::pointer& lpAccepted) SerializedTransaction::pointer stTxn = theApp->getMasterTransaction().fetch(item, false, 0); // XXX Need to support other results. // XXX Need to give failures too. - TransactionEngineResult terResult = terSUCCESS; + TransactionEngineResult terResult = tesSUCCESS; if (bAll) { diff --git a/src/TransactionEngine.cpp b/src/TransactionEngine.cpp index 3a40198743..19d17e4113 100644 --- a/src/TransactionEngine.cpp +++ b/src/TransactionEngine.cpp @@ -31,61 +31,50 @@ bool transResultInfo(TransactionEngineResult terCode, std::string& strToken, std const char* cpToken; const char* cpHuman; } transResultInfoA[] = { - { tenBAD_ADD_AUTH, "tenBAD_ADD_AUTH", "Not authorized to add account." }, - { tenBAD_AMOUNT, "tenBAD_AMOUNT", "Can only send positive amounts." }, - { tenBAD_CLAIM_ID, "tenBAD_CLAIM_ID", "Malformed." }, - { tenBAD_EXPIRATION, "tenBAD_EXPIRATION", "Malformed." }, - { tenBAD_GEN_AUTH, "tenBAD_GEN_AUTH", "Not authorized to claim generator." }, - { tenBAD_ISSUER, "tenBAD_ISSUER", "Malformed." }, - { tenBAD_OFFER, "tenBAD_OFFER", "Malformed." }, - { tenBAD_PATH, "tenBAD_PATH", "Malformed: path." }, - { tenBAD_PATH_COUNT, "tenBAD_PATH_COUNT", "Malformed: too many paths." }, - { tenBAD_PUBLISH, "tenBAD_PUBLISH", "Malformed: bad publish." }, - { 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." }, - { tenEXPIRED, "tenEXPIRED", "Won't add an expired offer." }, - { 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" }, - { terALREADY, "terALREADY", "The exact transaction was already in this ledger" }, - { terBAD_AUTH, "terBAD_AUTH", "Transaction's public key is not authorized." }, - { terBAD_AUTH_MASTER, "terBAD_AUTH_MASTER", "Auth for unclaimed account needs correct master key." }, - { terBAD_LEDGER, "terBAD_LEDGER", "Ledger in unexpected state." }, - { terBAD_RIPPLE, "terBAD_RIPPLE", "No ripple path can be satisfied." }, - { terBAD_SEQ, "terBAD_SEQ", "This sequence number should be zero for prepaid transactions." }, + { tefALREADY, "tefALREADY", "The exact transaction was already in this ledger" }, + { tefBAD_ADD_AUTH, "tefBAD_ADD_AUTH", "Not authorized to add account." }, + { tefBAD_AUTH, "tefBAD_AUTH", "Transaction's public key is not authorized." }, + { tefBAD_CLAIM_ID, "tefBAD_CLAIM_ID", "Malformed." }, + { tefBAD_GEN_AUTH, "tefBAD_GEN_AUTH", "Not authorized to claim generator." }, + { tefBAD_LEDGER, "tefBAD_LEDGER", "Ledger in unexpected state." }, + { tefCLAIMED, "tefCLAIMED", "Can not claim a previously claimed account." }, + { tefCREATED, "tefCREATED", "Can't add an already created account." }, + { tefGEN_IN_USE, "tefGEN_IN_USE", "Generator already in use." }, + { tefPAST_SEQ, "tefPAST_SEQ", "This sequence number has already past" }, + + { telBAD_PATH_COUNT, "telBAD_PATH_COUNT", "Malformed: too many paths." }, + { telINSUF_FEE_P, "telINSUF_FEE_P", "Fee insufficient." }, + + { temBAD_AMOUNT, "temBAD_AMOUNT", "Can only send positive amounts." }, + { temBAD_AUTH_MASTER, "temBAD_AUTH_MASTER", "Auth for unclaimed account needs correct master key." }, + { temBAD_EXPIRATION, "temBAD_EXPIRATION", "Malformed." }, + { temBAD_ISSUER, "temBAD_ISSUER", "Malformed." }, + { temBAD_OFFER, "temBAD_OFFER", "Malformed." }, + { temBAD_PUBLISH, "temBAD_PUBLISH", "Malformed: bad publish." }, + { temBAD_SET_ID, "temBAD_SET_ID", "Malformed." }, + { temCREATEXNS, "temCREATEXNS", "Can not specify non XNS for Create." }, + { temDST_IS_SRC, "temDST_IS_SRC", "Destination may not be source." }, + { temDST_NEEDED, "temDST_NEEDED", "Destination not specified." }, + { temINSUF_FEE_P, "temINSUF_FEE_P", "Fee not allowed." }, + { temINVALID, "temINVALID", "The transaction is ill-formed" }, + { temREDUNDANT, "temREDUNDANT", "Sends same currency to self." }, + { temRIPPLE_EMPTY, "temRIPPLE_EMPTY", "PathSet with no paths." }, + { temUNKNOWN, "temUNKNOWN", "The transactions requires logic not implemented yet" }, + { terDIR_FULL, "terDIR_FULL", "Can not add entry to full dir." }, { terFUNDS_SPENT, "terFUNDS_SPENT", "Can't set password, password set funds already spent." }, - { 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 directory node." }, - { terNODE_NOT_MENTIONED, "terNODE_NOT_MENTIONED", "Could not remove node from a directory." }, - { terNODE_NO_ROOT, "terNODE_NO_ROOT", "Directory doesn't exist." }, - { terNO_ACCOUNT, "terNO_ACCOUNT", "The source account does not exist" }, + { terINSUF_FEE_B, "terINSUF_FEE_B", "Account balance can't pay fee." }, + { 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" }, { terOFFER_NOT_FOUND, "terOFFER_NOT_FOUND", "Can not cancel offer." }, - { 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" }, { terPATH_EMPTY, "terPATH_EMPTY", "Path could not send partial amount." }, { terPATH_PARTIAL, "terPATH_PARTIAL", "Path could not send full amount." }, { 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." }, + + { tesSUCCESS, "tesSUCCESS", "The transaction was applied" }, }; int iIndex = NUMBER(transResultInfoA); @@ -433,7 +422,7 @@ TransactionEngineResult TransactionEngine::offerDelete(const SLE::pointer& sleOf uint64 uOwnerNode = sleOffer->getIFieldU64(sfOwnerNode); TransactionEngineResult terResult = dirDelete(false, uOwnerNode, Ledger::getOwnerDirIndex(uOwnerID), uOfferIndex); - if (terSUCCESS == terResult) + if (tesSUCCESS == terResult) { uint256 uDirectory = sleOffer->getIFieldH256(sfBookDirectory); uint64 uBookNode = sleOffer->getIFieldU64(sfBookNode); @@ -536,7 +525,7 @@ TransactionEngineResult TransactionEngine::dirAdd( Log(lsINFO) << "dirAdd: appending: Node: " << strHex(uNodeDir); // Log(lsINFO) << "dirAdd: appending: PREV: " << svIndexes.peekValue()[0].ToString(); - return terSUCCESS; + return tesSUCCESS; } // --> bKeepRoot: True, if we never completely clean up, after we overflow the root node. @@ -559,7 +548,7 @@ TransactionEngineResult TransactionEngine::dirDelete( { Log(lsWARNING) << "dirDelete: no such node"; - return terBAD_LEDGER; + return tefBAD_LEDGER; } STVector256 svIndexes = sleNode->getIFieldV256(sfIndexes); @@ -575,7 +564,7 @@ TransactionEngineResult TransactionEngine::dirDelete( Log(lsWARNING) << "dirDelete: no such entry"; - return terBAD_LEDGER; + return tefBAD_LEDGER; } // Remove the element. @@ -655,14 +644,14 @@ TransactionEngineResult TransactionEngine::dirDelete( { Log(lsWARNING) << "dirDelete: previous node is missing"; - return terBAD_LEDGER; + return tefBAD_LEDGER; } if (!sleNext) { Log(lsWARNING) << "dirDelete: next node is missing"; - return terBAD_LEDGER; + return tefBAD_LEDGER; } // Fix previous to point to its new next. @@ -704,7 +693,7 @@ TransactionEngineResult TransactionEngine::dirDelete( } } - return terSUCCESS; + return tesSUCCESS; } // Return the first entry and advance uDirEntry. @@ -775,7 +764,7 @@ TransactionEngineResult TransactionEngine::setAuthorized(const SerializedTransac { Log(lsWARNING) << "createGenerator: bad signature unauthorized generator claim"; - return tenBAD_GEN_AUTH; + return tefBAD_GEN_AUTH; } // Create generator. @@ -797,7 +786,7 @@ TransactionEngineResult TransactionEngine::setAuthorized(const SerializedTransac // Generator is already in use. Regular passphrases limited to one wallet. Log(lsWARNING) << "createGenerator: generator already in use"; - return tenGEN_IN_USE; + return tefGEN_IN_USE; } // Set the public key needed to use the account. @@ -807,7 +796,7 @@ TransactionEngineResult TransactionEngine::setAuthorized(const SerializedTransac mTxnAccount->setIFieldAccount(sfAuthorizedKey, uAuthKeyID); - return terSUCCESS; + return tesSUCCESS; } SLE::pointer TransactionEngine::entryCache(LedgerEntryType letType, const uint256& uIndex) @@ -842,9 +831,9 @@ SLE::pointer TransactionEngine::entryCreate(LedgerEntryType letType, const uint2 return sleNew; } -void TransactionEngine::entryDelete(SLE::pointer sleEntry, bool unfunded) +void TransactionEngine::entryDelete(SLE::pointer sleEntry, bool bUnfunded) { - mNodes.entryDelete(sleEntry, unfunded); + mNodes.entryDelete(sleEntry, bUnfunded); } void TransactionEngine::entryModify(SLE::pointer sleEntry) @@ -925,14 +914,14 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran } #endif - TransactionEngineResult terResult = terSUCCESS; + TransactionEngineResult terResult = tesSUCCESS; uint256 txID = txn.getTransactionID(); if (!txID) { Log(lsWARNING) << "applyTransaction: invalid transaction id"; - terResult = tenINVALID; + terResult = temINVALID; } // @@ -946,21 +935,21 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran // XXX This could be a lot cleaner to prevent unnecessary copying. NewcoinAddress naSigningPubKey; - if (terSUCCESS == terResult) + if (tesSUCCESS == terResult) naSigningPubKey = NewcoinAddress::createAccountPublic(txn.peekSigningPubKey()); // Consistency: really signed. - if ((terSUCCESS == terResult) && ((params & tepNO_CHECK_SIGN) == 0) && !txn.checkSign(naSigningPubKey)) + if ((tesSUCCESS == terResult) && ((params & tepNO_CHECK_SIGN) == 0) && !txn.checkSign(naSigningPubKey)) { Log(lsWARNING) << "applyTransaction: Invalid transaction: bad signature"; - terResult = tenINVALID; + terResult = temINVALID; } STAmount saCost = theConfig.FEE_DEFAULT; // Customize behavoir based on transaction type. - if (terSUCCESS == terResult) + if (tesSUCCESS == terResult) { switch (txn.getTxnType()) { @@ -997,27 +986,28 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran case ttINVALID: Log(lsWARNING) << "applyTransaction: Invalid transaction: ttINVALID transaction type"; - terResult = tenINVALID; + terResult = temINVALID; break; default: Log(lsWARNING) << "applyTransaction: Invalid transaction: unknown transaction type"; - terResult = tenUNKNOWN; + terResult = temUNKNOWN; break; } } STAmount saPaid = txn.getTransactionFee(); - if (terSUCCESS == terResult && (params & tepNO_CHECK_FEE) == tepNONE) + if (tesSUCCESS == terResult && (params & tepNO_CHECK_FEE) == tepNONE) { if (!!saCost) { + // XXX DO NOT CHECK ON CONSENSUS PASS if (saPaid < saCost) { Log(lsINFO) << "applyTransaction: insufficient fee"; - terResult = tenINSUF_FEE_P; + terResult = telINSUF_FEE_P; } } else @@ -1027,21 +1017,21 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran // Transaction is malformed. Log(lsWARNING) << "applyTransaction: fee not allowed"; - terResult = tenINSUF_FEE_P; + terResult = temINSUF_FEE_P; } } } // Get source account ID. mTxnAccountID = txn.getSourceAccount().getAccountID(); - if (terSUCCESS == terResult && !mTxnAccountID) + if (tesSUCCESS == terResult && !mTxnAccountID) { Log(lsWARNING) << "applyTransaction: bad source id"; - terResult = tenINVALID; + terResult = temINVALID; } - if (terSUCCESS != terResult) + if (tesSUCCESS != terResult) return terResult; boost::recursive_mutex::scoped_lock sl(mLedger->mLock); @@ -1069,7 +1059,7 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran } // Check if account claimed. - if (terSUCCESS == terResult) + if (tesSUCCESS == terResult) { switch (txn.getTxnType()) { @@ -1078,7 +1068,7 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran { Log(lsWARNING) << "applyTransaction: Account already claimed."; - terResult = tenCLAIMED; + terResult = tefCLAIMED; } break; @@ -1089,7 +1079,7 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran } // Consistency: Check signature - if (terSUCCESS == terResult) + if (tesSUCCESS == terResult) { switch (txn.getTxnType()) { @@ -1102,7 +1092,7 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran Log(lsWARNING) << "sourceAccountID: " << naSigningPubKey.humanAccountID(); Log(lsWARNING) << "txn accountID: " << txn.getSourceAccount().humanAccountID(); - terResult = tenBAD_CLAIM_ID; + terResult = tefBAD_CLAIM_ID; } break; @@ -1115,7 +1105,7 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran Log(lsWARNING) << "sourceAccountID: " << naSigningPubKey.humanAccountID(); Log(lsWARNING) << "txn accountID: " << txn.getSourceAccount().humanAccountID(); - terResult = tenBAD_SET_ID; + terResult = temBAD_SET_ID; } break; @@ -1135,13 +1125,13 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran { Log(lsINFO) << "applyTransaction: Delay: Not authorized to use account."; - terResult = terBAD_AUTH; + terResult = tefBAD_AUTH; } else { Log(lsINFO) << "applyTransaction: Invalid: Not authorized to use account."; - terResult = terBAD_AUTH_MASTER; + terResult = temBAD_AUTH_MASTER; } break; } @@ -1149,7 +1139,7 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran // Deduct the fee, so it's not available during the transaction. // Will only write the account back, if the transaction succeeds. - if (terSUCCESS != terResult || !saCost) + if (tesSUCCESS != terResult || !saCost) { nothing(); } @@ -1168,7 +1158,7 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran } // Validate sequence - if (terSUCCESS != terResult) + if (tesSUCCESS != terResult) { nothing(); } @@ -1190,13 +1180,13 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran { Log(lsWARNING) << "applyTransaction: duplicate sequence number"; - terResult = terALREADY; + terResult = tefALREADY; } else { Log(lsWARNING) << "applyTransaction: past sequence number"; - terResult = terPAST_SEQ; + terResult = tefPAST_SEQ; } } else @@ -1212,12 +1202,12 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran { Log(lsINFO) << "applyTransaction: bad sequence for pre-paid transaction"; - terResult = terPAST_SEQ; + terResult = tefPAST_SEQ; } } mTxnAccount->setIFieldU32(sfLastSignedSeq, mLedger->getLedgerSeq()); - if (terSUCCESS == terResult) + if (tesSUCCESS == terResult) { entryModify(mTxnAccount); @@ -1237,7 +1227,7 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran case ttINVALID: Log(lsINFO) << "applyTransaction: invalid type"; - terResult = tenINVALID; + terResult = temINVALID; break; case ttINVOICE: @@ -1273,7 +1263,7 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran break; default: - terResult = tenUNKNOWN; + terResult = temUNKNOWN; break; } } @@ -1285,7 +1275,7 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran Log(lsINFO) << "applyTransaction: terResult=" << strToken << " : " << terResult << " : " << strHuman; - if (terSUCCESS == terResult) + if (tesSUCCESS == terResult) { txnWrite(); @@ -1365,12 +1355,6 @@ TransactionEngineResult TransactionEngine::doAccountSet(const SerializedTransact { nothing(); } - else if (mTxnAccount->getIFieldPresent(sfMessageKey)) - { - Log(lsINFO) << "doAccountSet: can not change message key"; - - return tenMSG_SET; - } else { Log(lsINFO) << "doAccountSet: set message key"; @@ -1433,7 +1417,7 @@ TransactionEngineResult TransactionEngine::doAccountSet(const SerializedTransact { Log(lsINFO) << "doAccountSet: bad publish"; - return tenBAD_PUBLISH; + return temBAD_PUBLISH; } else if (bPublishHash && bPublishSize) { @@ -1458,7 +1442,7 @@ TransactionEngineResult TransactionEngine::doAccountSet(const SerializedTransact Log(lsINFO) << "doAccountSet<"; - return terSUCCESS; + return tesSUCCESS; } TransactionEngineResult TransactionEngine::doClaim(const SerializedTransaction& txn) @@ -1474,7 +1458,7 @@ TransactionEngineResult TransactionEngine::doClaim(const SerializedTransaction& TransactionEngineResult TransactionEngine::doCreditSet(const SerializedTransaction& txn) { - TransactionEngineResult terResult = terSUCCESS; + TransactionEngineResult terResult = tesSUCCESS; Log(lsINFO) << "doCreditSet>"; // Check if destination makes sense. @@ -1484,13 +1468,13 @@ TransactionEngineResult TransactionEngine::doCreditSet(const SerializedTransacti { Log(lsINFO) << "doCreditSet: Invalid transaction: Destination account not specifed."; - return tenDST_NEEDED; + return temDST_NEEDED; } else if (mTxnAccountID == uDstAccountID) { Log(lsINFO) << "doCreditSet: Invalid transaction: Can not extend credit to self."; - return tenDST_IS_SRC; + return temDST_IS_SRC; } SLE::pointer sleDst = entryCache(ltACCOUNT_ROOT, Ledger::getAccountRootIndex(uDstAccountID)); @@ -1603,7 +1587,7 @@ TransactionEngineResult TransactionEngine::doCreditSet(const SerializedTransacti terResult = dirAdd(uSrcRef, Ledger::getOwnerDirIndex(mTxnAccountID), sleRippleState->getIndex()); - if (terSUCCESS == terResult) + if (tesSUCCESS == terResult) terResult = dirAdd(uSrcRef, Ledger::getOwnerDirIndex(uDstAccountID), sleRippleState->getIndex()); } @@ -1655,7 +1639,7 @@ TransactionEngineResult TransactionEngine::doNicknameSet(const SerializedTransac std::cerr << "doNicknameSet<" << std::endl; - return terSUCCESS; + return tesSUCCESS; } TransactionEngineResult TransactionEngine::doPasswordFund(const SerializedTransaction& txn) @@ -1689,7 +1673,7 @@ TransactionEngineResult TransactionEngine::doPasswordFund(const SerializedTransa std::cerr << "doPasswordFund<" << std::endl; - return terSUCCESS; + return tesSUCCESS; } TransactionEngineResult TransactionEngine::doPasswordSet(const SerializedTransaction& txn) @@ -1722,7 +1706,7 @@ TransactionEngineResult TransactionEngine::doPasswordSet(const SerializedTransac // <-- pnDst.saReceive // <-- pnDst.saIOUForgive // <-- pnDst.saIOUAccept -// <-- terResult : terSUCCESS = no error and if !bAllowPartial complelely satisfied wanted. +// <-- terResult : tesSUCCESS = no error and if !bAllowPartial complelely satisfied wanted. // <-> usOffersDeleteAlways: // <-> usOffersDeleteOnSuccess: TransactionEngineResult calcOfferFill(paymentNode& pnSrc, paymentNode& pnDst, bool bAllowPartial) @@ -1756,7 +1740,7 @@ TransactionEngineResult calcOfferFill(paymentNode& pnSrc, paymentNode& pnDst, bo pnDst.saIOUForgive, bAllowPartial); - if (terSUCCESS == terResult) + if (tesSUCCESS == terResult) { // Issue to wanted. terResult = calcOfferFill( @@ -1766,7 +1750,7 @@ TransactionEngineResult calcOfferFill(paymentNode& pnSrc, paymentNode& pnDst, bo bAllowPartial); } - if (terSUCCESS == terResult && !bAllowPartial) + if (tesSUCCESS == terResult && !bAllowPartial) { STAmount saTotal = pnDst.saIOUForgive + pnSrc.saIOUAccept; @@ -2147,6 +2131,7 @@ bool TransactionEngine::calcNodeOfferFwd( while (saPrvDlvReq != saPrvDlvAct // Have not met request. && dirNext(uDirectTip, sleDirectDir, uEntry, uCurIndex)) { + // Have an entry from the directory. SLE::pointer sleCurOfr = entryCache(ltOFFER, uCurIndex); uint160 uCurOfrAccountID = sleCurOfr->getIValueFieldAccount(sfAccount).getAccountID(); const STAmount& saCurOfrOutReq = sleCurOfr->getIValueFieldAmount(sfTakerGets); @@ -2155,7 +2140,33 @@ bool TransactionEngine::calcNodeOfferFwd( STAmount saCurOfrFunds = accountFunds(uCurOfrAccountID, saCurOfrOutReq); // Funds left. STAmount saCurOfrInMax = MIN(saCurOfrInReq, saPrvDlvReq-saPrvDlvAct); - if (!!uNxtAccountID) + if (!saCurOfrFunds) + { +#ifdef WORK_IN_PROGRESS + // Offer is unfunded. + pspCur->usUnfunded.add(uCurIndex); // Add offer to found unfunded. + + entryDelete(sleCurOfr, true); // Delete unfunded offer. + + // Delete unfunded offer from owner's directory. + const uint64 uOwnerNode = sleCurOffer->getIFieldU64(sfOwnerNode); + + terResult = dirDelete( + true, // YYY We don't delete owner directories? + uOwnerNode, + uDirectTip, + uCurIndex); + + // Delete unfunded offer from quality directory. + // XXX Need a dir walking version of delete. + terResult = dirDelete( + false, // Don't need to keep root. + const uint64& uNodeDir, + uDirectTip, + uCurIndex); +#endif + } + else if (!!uNxtAccountID) { // Next is an account. @@ -2165,19 +2176,24 @@ bool TransactionEngine::calcNodeOfferFwd( const bool bFee = saFeeRate != saOne; const STAmount saOutPass = STAmount::divide(saCurOfrInMax, saOfrRate, uCurCurrencyID, uCurIssuerID); - const STAmount saOutBase = MIN(saCurOfrOutReq, saOutPass); // Limit offer out by needed. - const STAmount saOutCost = MIN( - bFee - ? STAmount::multiply(saOutBase, saFeeRate, uCurCurrencyID, uCurIssuerID) - : saOutBase, - saCurOfrFunds); // Limit cost by fees & funds. + const STAmount saOutBase = MIN(saCurOfrOutReq, saOutPass); // Limit offer out by needed. + const STAmount saOutCostRaw= bFee + ? STAmount::multiply(saOutBase, saFeeRate, uCurCurrencyID, uCurIssuerID) + : saOutBase; + const STAmount saOutCost = MIN(saOutCostRaw, saCurOfrFunds); // Limit cost by fees & funds. const STAmount saOutDlvAct = bFee ? STAmount::divide(saOutCost, saFeeRate, uCurCurrencyID, uCurIssuerID) - : saOutCost; // Out amount after fees. + : saOutCost; // Out amount after fees. // Compute input w/o fees required. const STAmount saInDlvAct = STAmount::multiply(saOutDlvAct, saOfrRate, uCurCurrencyID, uCurIssuerID); + // XXX Send from offer owner +// accountSend(uCurIssuerID, uNxtAccountID, saOutDlvAct); + saCurDlvAct += saOutDlvAct; // Portion of driver served. + +// XXX accountCredit(uCurIssuerID, uNxtAccountID, saOutDlvAct); + saPrvDlvAct += saInDlvAct; // Portion needed in previous. } else @@ -2298,7 +2314,7 @@ void TransactionEngine::calcNodeOffer( STAmount& saGot ) const { - TransactionEngineResult terResult = tenUNKNOWN; + TransactionEngineResult terResult = temUNKNOWN; // Direct: not bridging via XNS bool bDirectNext = true; // True, if need to load. @@ -2425,10 +2441,10 @@ void TransactionEngine::calcNodeOffer( { // No more offers. Declare success, even if none returned. saGot = saWanted-saNeed; - terResult = terSUCCESS; + terResult = tesSUCCESS; } - if (terSUCCESS != terResult) + if (tesSUCCESS != terResult) { STAmount& saAvailIn = bUseBridge ? saBridgeIn : saDirectIn; STAmount& saAvailOut = bUseBridge ? saBridgeOut : saDirectOut; @@ -2700,7 +2716,7 @@ bool TransactionEngine::calcNodeAccountRev(unsigned int uIndex, PathState::point if (!saCurWantedAct) { // Must have processed something. - // terResult = tenBAD_AMOUNT; + // terResult = temBAD_AMOUNT; bSuccess = false; } } @@ -2761,7 +2777,7 @@ bool TransactionEngine::calcNodeAccountRev(unsigned int uIndex, PathState::point if (!saCurRedeemAct && !saCurIssueAct) { // Must want something. - // terResult = tenBAD_AMOUNT; + // terResult = temBAD_AMOUNT; bSuccess = false; } @@ -2807,7 +2823,7 @@ bool TransactionEngine::calcNodeAccountRev(unsigned int uIndex, PathState::point if (!saCurDeliverAct) { // Must want something. - // terResult = tenBAD_AMOUNT; + // terResult = temBAD_AMOUNT; bSuccess = false; } @@ -2839,7 +2855,7 @@ bool TransactionEngine::calcNodeAccountRev(unsigned int uIndex, PathState::point if (!saCurWantedAct) { // Must have processed something. - // terResult = tenBAD_AMOUNT; + // terResult = temBAD_AMOUNT; bSuccess = false; } } @@ -2877,7 +2893,7 @@ bool TransactionEngine::calcNodeAccountRev(unsigned int uIndex, PathState::point if (!saPrvDeliverAct) { // Must want something. - // terResult = tenBAD_AMOUNT; + // terResult = temBAD_AMOUNT; bSuccess = false; } } @@ -2898,7 +2914,7 @@ bool TransactionEngine::calcNodeAccountRev(unsigned int uIndex, PathState::point if (!saCurDeliverAct) { // Must want something. - // terResult = tenBAD_AMOUNT; + // terResult = temBAD_AMOUNT; bSuccess = false; } } @@ -3196,6 +3212,12 @@ bool PathState::lessPriority(const PathState::pointer& lhs, const PathState::poi } // Make sure the path delivers to uAccountID: uCurrencyID from uIssuerID. +// +// Rules: +// - Currencies must be converted via an offer. +// - A node names it's output. +// - A ripple nodes output issuer must be the node's account or the next node's account. +// - Offers can only go directly to another offer if the currency and issuer are an exact match. bool PathState::pushImply(uint160 uAccountID, uint160 uCurrencyID, uint160 uIssuerID) { const paymentNode& pnPrv = vpnNodes.back(); @@ -3209,23 +3231,6 @@ bool PathState::pushImply(uint160 uAccountID, uint160 uCurrencyID, uint160 uIssu if (pnPrv.uCurrencyID != uCurrencyID) { // Need to convert via an offer. -#if 0 -// XXX Don't know if need this. - bool bPrvAccount = !!pnPrv.uAccountID; - - if (!bPrvAccount) // Previous is an offer. - { - // Direct offer --> offer is not allowed for non-stamps. - // Need to ripple through uIssuerID's account. - - bValid = pushNode( - STPathElement::typeAccount - | STPathElement::typeIssue, - pnPrv.uIssuerID, // Intermediate account is the needed issuer. - CURRENCY_ONE, // Inherit from previous. - ACCOUNT_ONE); // Default same as account. - } -#endif bValid = pushNode( STPathElement::typeCurrency // Offer. @@ -3550,7 +3555,8 @@ Json::Value PathState::getJson() const } // Calculate a node and its previous nodes. -// From the destination work towards the source calculating how much must be asked for. +// From the destination work in reverse towards the source calculating how much must be asked for. +// Then work forward, figuring out how much can actually be delivered. // --> bAllowPartial: If false, fail if can't meet requirements. // <-- bValid: true=success, false=insufficient funds / liqudity. // <-> pnNodes: @@ -3643,13 +3649,13 @@ TransactionEngineResult TransactionEngine::doPayment(const SerializedTransaction { Log(lsINFO) << "doPayment: Invalid transaction: Payment destination account not specifed."; - return tenDST_NEEDED; + return temDST_NEEDED; } else if (!saDstAmount.isPositive()) { Log(lsINFO) << "doPayment: Invalid transaction: bad amount: " << saDstAmount.getHumanCurrency() << " " << saDstAmount.getText(); - return tenBAD_AMOUNT; + return temBAD_AMOUNT; } else if (mTxnAccountID == uDstAccountID && uSrcCurrency == uDstCurrency && !bPaths) { @@ -3659,7 +3665,7 @@ TransactionEngineResult TransactionEngine::doPayment(const SerializedTransaction % uSrcCurrency.ToString() % uDstCurrency.ToString()); - return tenREDUNDANT; + return temREDUNDANT; } else if (bMax && ((saMaxAmount == saDstAmount && saMaxAmount.getCurrency() == saDstAmount.getCurrency()) @@ -3667,7 +3673,7 @@ TransactionEngineResult TransactionEngine::doPayment(const SerializedTransaction { Log(lsINFO) << "doPayment: Invalid transaction: bad SendMax."; - return tenINVALID; + return temINVALID; } SLE::pointer sleDst = entryCache(ltACCOUNT_ROOT, Ledger::getAccountRootIndex(uDstAccountID)); @@ -3679,7 +3685,7 @@ TransactionEngineResult TransactionEngine::doPayment(const SerializedTransaction // This restriction could be relaxed. Log(lsINFO) << "doPayment: Invalid transaction: Create account may only fund XNS."; - return tenCREATEXNS; + return temCREATEXNS; } else if (!bCreate) { @@ -3718,112 +3724,26 @@ TransactionEngineResult TransactionEngine::doPayment(const SerializedTransaction mTxnAccount->setIFieldAmount(sfBalance, saSrcXNSBalance - saDstAmount); sleDst->setIFieldAmount(sfBalance, sleDst->getIValueFieldAmount(sfBalance) + saDstAmount); - return terSUCCESS; + return tesSUCCESS; } // // Ripple payment // -#if 0 -// Disabled to make sure full ripple code is correct. - // Try direct ripple first. - if (!bNoRippleDirect && mTxnAccountID != uDstAccountID && uSrcCurrency == uDstCurrency) - { - // XXX Does not handle quality. - SLE::pointer sleRippleState = entryCache(ltRIPPLE_STATE, Ledger::getRippleStateIndex(mTxnAccountID, 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. - uint160 uLowID = sleRippleState->getIValueFieldAccount(sfLowID).getAccountID(); - uint160 uHighID = sleRippleState->getIValueFieldAccount(sfHighID).getAccountID(); - bool bSendHigh = uLowID == mTxnAccountID && uHighID == uDstAccountID; - bool bSendLow = uLowID == uDstAccountID && uHighID == mTxnAccountID; - // 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) - { - // 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( - uSrcRef, - Ledger::getOwnerDirIndex(mTxnAccountID), // 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); - entryModify(sleRippleState); - - return terSUCCESS; - } - } -#endif - STPathSet spsPaths = txn.getITFieldPathSet(sfPaths); if (bNoRippleDirect && spsPaths.isEmpty()) { Log(lsINFO) << "doPayment: Invalid transaction: No paths and direct ripple not allowed."; - return tenRIPPLE_EMPTY; + return temRIPPLE_EMPTY; } + // XXX Skip check if final processing. if (spsPaths.getPathCount() > RIPPLE_PATHS_MAX) { - return tenBAD_PATH_COUNT; + return telBAD_PATH_COUNT; } // Incrementally search paths. @@ -3874,9 +3794,10 @@ TransactionEngineResult TransactionEngine::doPayment(const SerializedTransaction TransactionEngineResult terResult; STAmount saPaid; STAmount saWanted; + LedgerEntrySet lesBase = mNodes; // Checkpoint with just fees paid. - terResult = tenUNKNOWN; - while (tenUNKNOWN == terResult) + terResult = temUNKNOWN; + while (temUNKNOWN == terResult) { PathState::pointer pspBest; LedgerEntrySet lesCheckpoint = mNodes; @@ -3903,25 +3824,29 @@ TransactionEngineResult TransactionEngine::doPayment(const SerializedTransaction mNodes.swapWith(pspBest->lesEntries); // Figure out if done. - if (tenUNKNOWN == terResult && saPaid == saWanted) + if (temUNKNOWN == terResult && saPaid == saWanted) { - terResult = terSUCCESS; + terResult = tesSUCCESS; } } - // Ran out of paths. + // Not done and ran out of paths. else if (!bPartialPayment) { // Partial payment not allowed. - terResult = terPATH_PARTIAL; // XXX No effect, except unfunded and charge fee. + terResult = terPATH_PARTIAL; + mNodes = lesBase; // Revert to just fees charged. } + // Partial payment ok. else if (!saPaid) { - // Nothing claimed. - terResult = terPATH_EMPTY; // XXX No effect except unfundeds and charge fee. + // No payment at all. + // XXX Mark for retry? + terResult = terPATH_EMPTY; + mNodes = lesBase; // Revert to just fees charged. } else { - terResult = terSUCCESS; + terResult = tesSUCCESS; } } @@ -3954,7 +3879,7 @@ TransactionEngineResult TransactionEngine::doWalletAdd(const SerializedTransacti { std::cerr << "WalletAdd: unauthorized: bad signature " << std::endl; - return tenBAD_ADD_AUTH; + return tefBAD_ADD_AUTH; } SLE::pointer sleDst = entryCache(ltACCOUNT_ROOT, Ledger::getAccountRootIndex(uDstAccountID)); @@ -3963,7 +3888,7 @@ TransactionEngineResult TransactionEngine::doWalletAdd(const SerializedTransacti { std::cerr << "WalletAdd: account already created" << std::endl; - return tenCREATED; + return tefCREATED; } STAmount saAmount = txn.getITFieldAmount(sfAmount); @@ -3993,12 +3918,12 @@ TransactionEngineResult TransactionEngine::doWalletAdd(const SerializedTransacti std::cerr << "WalletAdd<" << std::endl; - return terSUCCESS; + return tesSUCCESS; } TransactionEngineResult TransactionEngine::doInvoice(const SerializedTransaction& txn) { - return tenUNKNOWN; + return temUNKNOWN; } // Take as much as possible. Adjusts account balances. Charges fees on top to taker. @@ -4007,7 +3932,7 @@ TransactionEngineResult TransactionEngine::doInvoice(const SerializedTransaction // --> saTakerGets: What the taker wanted (w/ issuer) // <-- saTakerPaid: What taker paid not including fees. To reduce an offer. // <-- saTakerGot: What taker got not including fees. To reduce an offer. -// <-- terResult: terSUCCESS or terNO_ACCOUNT +// <-- terResult: tesSUCCESS or terNO_ACCOUNT // Note: All SLE modifications must always occur even on failure. // XXX: Fees should be paid by the source of the currency. TransactionEngineResult TransactionEngine::takeOffers( @@ -4031,12 +3956,12 @@ TransactionEngineResult TransactionEngine::takeOffers( const uint160 uTakerPaysCurrency = saTakerPays.getCurrency(); const uint160 uTakerGetsAccountID = saTakerGets.getIssuer(); const uint160 uTakerGetsCurrency = saTakerGets.getCurrency(); - TransactionEngineResult terResult = tenUNKNOWN; + TransactionEngineResult terResult = temUNKNOWN; saTakerPaid = 0; saTakerGot = 0; - while (tenUNKNOWN == terResult) + while (temUNKNOWN == terResult) { SLE::pointer sleOfferDir; uint64 uTipQuality; @@ -4068,7 +3993,7 @@ TransactionEngineResult TransactionEngine::takeOffers( // Done. Log(lsINFO) << "takeOffers: done"; - terResult = terSUCCESS; + terResult = tesSUCCESS; } else { @@ -4221,7 +4146,7 @@ Log(lsWARNING) << "doOfferCreate: saTakerGets=" << saTakerGets.getFullText(); const uint160 uGetsCurrency = saTakerGets.getCurrency(); const uint64 uRate = STAmount::getRate(saTakerGets, saTakerPays); - TransactionEngineResult terResult = terSUCCESS; + TransactionEngineResult terResult = tesSUCCESS; uint256 uDirectory; // Delete hints. uint64 uOwnerNode; uint64 uBookNode; @@ -4230,37 +4155,38 @@ Log(lsWARNING) << "doOfferCreate: saTakerGets=" << saTakerGets.getFullText(); { Log(lsWARNING) << "doOfferCreate: Malformed offer: bad expiration"; - terResult = tenBAD_EXPIRATION; + terResult = temBAD_EXPIRATION; } else if (bHaveExpiration && mLedger->getParentCloseTimeNC() >= uExpiration) { Log(lsWARNING) << "doOfferCreate: Expired transaction: offer expired"; - terResult = tenEXPIRED; + // XXX CHARGE FEE ONLY. + terResult = tesSUCCESS; } else if (saTakerPays.isNative() && saTakerGets.isNative()) { Log(lsWARNING) << "doOfferCreate: Malformed offer: XNS for XNS"; - terResult = tenBAD_OFFER; + terResult = temBAD_OFFER; } else if (!saTakerPays || !saTakerGets) { Log(lsWARNING) << "doOfferCreate: Malformed offer: bad amount"; - terResult = tenBAD_OFFER; + terResult = temBAD_OFFER; } else if (uPaysCurrency == uGetsCurrency && uPaysIssuerID == uGetsIssuerID) { Log(lsWARNING) << "doOfferCreate: Malformed offer: redundant offer"; - terResult = tenREDUNDANT; + terResult = temREDUNDANT; } else if (saTakerPays.isNative() != !uPaysIssuerID || saTakerGets.isNative() != !uGetsIssuerID) { Log(lsWARNING) << "doOfferCreate: Malformed offer: bad issuer"; - terResult = tenBAD_ISSUER; + terResult = temBAD_ISSUER; } else if (!accountFunds(mTxnAccountID, saTakerGets).isPositive()) { @@ -4269,7 +4195,7 @@ Log(lsWARNING) << "doOfferCreate: saTakerGets=" << saTakerGets.getFullText(); terResult = terUNFUNDED; } - if (terSUCCESS == terResult && !saTakerPays.isNative()) + if (tesSUCCESS == terResult && !saTakerPays.isNative()) { SLE::pointer sleTakerPays = entryCache(ltACCOUNT_ROOT, Ledger::getAccountRootIndex(uPaysIssuerID)); @@ -4281,7 +4207,7 @@ Log(lsWARNING) << "doOfferCreate: saTakerGets=" << saTakerGets.getFullText(); } } - if (terSUCCESS == terResult) + if (tesSUCCESS == terResult) { STAmount saOfferPaid; STAmount saOfferGot; @@ -4312,7 +4238,7 @@ Log(lsWARNING) << "doOfferCreate: saTakerGets=" << saTakerGets.getFullText(); Log(lsWARNING) << "doOfferCreate: takeOffers: saTakerPays=" << saTakerPays.getFullText(); Log(lsWARNING) << "doOfferCreate: takeOffers: saTakerGets=" << saTakerGets.getFullText(); - if (terSUCCESS == terResult) + if (tesSUCCESS == terResult) { saTakerPays -= saOfferGot; // Reduce payin from takers by what offer just got. saTakerGets -= saOfferPaid; // Reduce payout to takers by what srcAccount just paid. @@ -4328,7 +4254,7 @@ Log(lsWARNING) << "doOfferCreate: saTakerGets=" << saTakerGets.getFullText(); // Log(lsWARNING) << "doOfferCreate: takeOffers: uPaysIssuerID=" << NewcoinAddress::createHumanAccountID(uPaysIssuerID); // Log(lsWARNING) << "doOfferCreate: takeOffers: uGetsIssuerID=" << NewcoinAddress::createHumanAccountID(uGetsIssuerID); - if (terSUCCESS == terResult + if (tesSUCCESS == terResult && !!saTakerPays // Still wanting something. && !!saTakerGets // Still offering something. && accountFunds(mTxnAccountID, saTakerGets).isPositive()) // Still funded. @@ -4338,7 +4264,7 @@ Log(lsWARNING) << "doOfferCreate: saTakerGets=" << saTakerGets.getFullText(); // Add offer to owner's directory. terResult = dirAdd(uOwnerNode, Ledger::getOwnerDirIndex(mTxnAccountID), uLedgerIndex); - if (terSUCCESS == terResult) + if (tesSUCCESS == terResult) { uint256 uBookBase = Ledger::getBookBase(uPaysCurrency, uPaysIssuerID, uGetsCurrency, uGetsIssuerID); @@ -4355,7 +4281,7 @@ Log(lsWARNING) << "doOfferCreate: saTakerGets=" << saTakerGets.getFullText(); terResult = dirAdd(uBookNode, uDirectory, uLedgerIndex); } - if (terSUCCESS == terResult) + if (tesSUCCESS == terResult) { // Log(lsWARNING) << "doOfferCreate: uPaysIssuerID=" << NewcoinAddress::createHumanAccountID(uPaysIssuerID); // Log(lsWARNING) << "doOfferCreate: uGetsIssuerID=" << NewcoinAddress::createHumanAccountID(uGetsIssuerID); @@ -4411,17 +4337,17 @@ TransactionEngineResult TransactionEngine::doOfferCancel(const SerializedTransac TransactionEngineResult TransactionEngine::doTake(const SerializedTransaction& txn) { - return tenUNKNOWN; + return temUNKNOWN; } TransactionEngineResult TransactionEngine::doStore(const SerializedTransaction& txn) { - return tenUNKNOWN; + return temUNKNOWN; } TransactionEngineResult TransactionEngine::doDelete(const SerializedTransaction& txn) { - return tenUNKNOWN; + return temUNKNOWN; } // vim:ts=4 diff --git a/src/TransactionEngine.h b/src/TransactionEngine.h index 6204650fe4..990bc8061d 100644 --- a/src/TransactionEngine.h +++ b/src/TransactionEngine.h @@ -14,75 +14,71 @@ enum TransactionEngineResult { - // Note: Numbers are currently unstable. Use tokens. + // Note: Range is stable. Exact numbers are currently unstable. Use tokens. - // tenCAN_NEVER_SUCCEED = <0 + // -399 .. -300: L Local error (transaction fee inadequate, exceeds local limit) + // Not forwarded, no fee. Only valid during non-consensus processing + telLOCAL_ERROR = -399, + telBAD_PATH_COUNT, + telINSUF_FEE_P, - // Malformed: Fee claimed - tenGEN_IN_USE = -300, - tenBAD_ADD_AUTH, - tenBAD_AMOUNT, - tenBAD_CLAIM_ID, - tenBAD_EXPIRATION, - tenBAD_GEN_AUTH, - tenBAD_ISSUER, - tenBAD_OFFER, - tenBAD_PATH, - tenBAD_PATH_COUNT, - tenBAD_PUBLISH, - tenBAD_SET_ID, - tenCREATEXNS, - tenDST_IS_SRC, - tenDST_NEEDED, - tenEXPLICITXNS, - tenREDUNDANT, - tenRIPPLE_EMPTY, + // -299 .. -200: M Malformed (bad signature) + // Transaction corrupt, not forwarded, cannot charge fee, reject + // Never can succeed in any ledger + temMALFORMED = -299, + temBAD_AMOUNT, + temBAD_AUTH_MASTER, + temBAD_EXPIRATION, + temBAD_ISSUER, + temBAD_OFFER, + temBAD_PUBLISH, + temBAD_SET_ID, + temCREATEXNS, + temDST_IS_SRC, + temDST_NEEDED, + temINSUF_FEE_P, + temINVALID, + temREDUNDANT, + temRIPPLE_EMPTY, + temUNKNOWN, - // Invalid: Ledger won't allow. - tenCLAIMED = -200, - tenBAD_RIPPLE, - tenCREATED, - tenEXPIRED, - tenMSG_SET, - terALREADY, + // -199 .. -100: F Failure (sequence number previously used) + // Transaction cannot succeed because of ledger state, unexpected ledger state, C++ exception, not forwarded, cannot be + // applied, Could succeed in an imaginary ledger. + tefFAILURE = -199, + tefALREADY, + tefBAD_ADD_AUTH, + tefBAD_AUTH, + tefBAD_CLAIM_ID, + tefBAD_GEN_AUTH, + tefBAD_LEDGER, + tefCLAIMED, + tefCREATED, + tefGEN_IN_USE, + tefPAST_SEQ, - // Other - tenFAILED = -100, - 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_AUTH_MASTER, - terBAD_LEDGER, - terBAD_RIPPLE, - terBAD_SEQ, - terCREATED, + // -99 .. -1: R Retry (sequence too high, no funds for txn fee, originating account non-existent) + // Transaction cannot be applied, cannot charge fee, not forwarded, might succeed later, hold + terRETRY = -99, terDIR_FULL, terFUNDS_SPENT, terINSUF_FEE_B, - terINSUF_FEE_T, - terNODE_NOT_FOUND, - terNODE_NOT_MENTIONED, - terNODE_NO_ROOT, terNO_ACCOUNT, terNO_DST, terNO_LINE_NO_ZERO, - terNO_PATH, - terOFFER_NOT_FOUND, - terOVER_LIMIT, - terPAST_LEDGER, - terPAST_SEQ, + terOFFER_NOT_FOUND, // XXX If we check sequence first this could be hard failure. terPRE_SEQ, terSET_MISSING_DST, - terUNCLAIMED, terUNFUNDED, + // 0: S Success (success) + // Transaction succeeds, can be applied, can charge fee, forwarded + tesSUCCESS = 0, + + // 100 .. P Partial success (SR) (ripple transaction with no good paths, pay to non-existent account) + // Transaction can be applied, can charge fee, forwarded, but does not achieve optimal result. + tesPARITAL = 100, + // Might succeed in different order. // XXX claim fee and try to delete unfunded. terPATH_EMPTY, @@ -133,9 +129,19 @@ protected: public: typedef boost::shared_ptr pointer; - bool bValid; - std::vector vpnNodes; - LedgerEntrySet lesEntries; + bool bValid; + std::vector vpnNodes; + + // If the transaction fails to meet some constraint, still need to delete unfunded offers. + boost::unordered_set usUnfundedFound; // Offers that were found unfunded. + + // When processing, don't want to complicate directory walking with deletion. + std::vector vUnfundedBecame; // Offers that became unfunded. + + // First time working in reverse a funding source was mentioned. Source may only be used there. + boost::unordered_map, int> umSource; // Map of currency, issuer to node index. + + LedgerEntrySet lesEntries; int mIndex; uint64 uQuality; // 0 = none. @@ -222,7 +228,7 @@ protected: SLE::pointer entryCreate(LedgerEntryType letType, const uint256& uIndex); SLE::pointer entryCache(LedgerEntryType letType, const uint256& uIndex); - void entryDelete(SLE::pointer sleEntry, bool unfunded = false); + void entryDelete(SLE::pointer sleEntry, bool bUnfunded = false); void entryModify(SLE::pointer sleEntry); uint32 rippleTransferRate(const uint160& uIssuerID); From 9148127083ea1b27c53152717d2289b66ee77d6e Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 27 Aug 2012 03:04:33 -0700 Subject: [PATCH 10/10] Fix threading. --- src/LedgerEntrySet.cpp | 34 +++++++++++++++++++++------------- src/LedgerEntrySet.h | 6 +++--- src/TransactionMeta.cpp | 33 ++++++++------------------------- src/TransactionMeta.h | 7 ++++--- 4 files changed, 36 insertions(+), 44 deletions(-) diff --git a/src/LedgerEntrySet.cpp b/src/LedgerEntrySet.cpp index 06a718b52c..f6ba5405a2 100644 --- a/src/LedgerEntrySet.cpp +++ b/src/LedgerEntrySet.cpp @@ -259,31 +259,38 @@ SLE::pointer LedgerEntrySet::getForMod(const uint256& node, Ledger::pointer& led } -bool LedgerEntrySet::threadNode(SLE::pointer& node, const NewcoinAddress& threadTo, Ledger::pointer& ledger, +bool LedgerEntrySet::threadTx(TransactionMetaNode& metaNode, const NewcoinAddress& threadTo, Ledger::pointer& ledger, boost::unordered_map& newMods) { SLE::pointer sle = getForMod(Ledger::getAccountRootIndex(threadTo.getAccountID()), ledger, newMods); - if ((!sle) || (sle->getIndex() == node->getIndex())) // do not self-thread + if (!sle) return false; - return threadNode(node, sle, ledger, newMods); + return threadTx(metaNode, sle, ledger, newMods); } -bool LedgerEntrySet::threadNode(SLE::pointer& node, SLE::pointer& threadTo, Ledger::pointer& ledger, +bool LedgerEntrySet::threadTx(TransactionMetaNode& metaNode, SLE::pointer& threadTo, Ledger::pointer& ledger, boost::unordered_map& newMods) -{ - // WRITEME +{ // node = the node that was modified/deleted/created + // threadTo = the node that needs to know + uint256 prevTxID; + uint32 prevLgrID; + if (!threadTo->thread(mSet.getTxID(), mSet.getLgrSeq(), prevTxID, prevLgrID)) + return false; + if (metaNode.thread(prevTxID, prevLgrID)) + return true; + assert(false); return false; } -bool LedgerEntrySet::threadOwners(SLE::pointer& node, Ledger::pointer& ledger, +bool LedgerEntrySet::threadOwners(TransactionMetaNode& metaNode, SLE::pointer& node, Ledger::pointer& ledger, boost::unordered_map& newMods) { // thread new or modified node to owner or owners if (node->hasOneOwner()) // thread to owner's account - return threadNode(node, node->getOwner(), ledger, newMods); + return threadTx(metaNode, node->getOwner(), ledger, newMods); else if (node->hasTwoOwners()) // thread to owner's accounts return - threadNode(node, node->getFirstOwner(), ledger, newMods) || - threadNode(node, node->getSecondOwner(), ledger, newMods); + threadTx(metaNode, node->getFirstOwner(), ledger, newMods) || + threadTx(metaNode, node->getSecondOwner(), ledger, newMods); else return false; } @@ -318,10 +325,11 @@ void LedgerEntrySet::calcRawMeta(Serializer& s, Ledger::pointer& origLedger) { SLE::pointer origNode = origLedger->getSLE(it->first); SLE::pointer curNode = it->second.mEntry; + TransactionMetaNode &metaNode = mSet.getAffectedNode(it->first, nType); if (nType == TMNDeletedNode) { - threadOwners(origNode, origLedger, newMod); + threadOwners(metaNode, origNode, origLedger, newMod); if (origNode->getType() == ltOFFER) { // check for non-zero balances @@ -332,10 +340,10 @@ void LedgerEntrySet::calcRawMeta(Serializer& s, Ledger::pointer& origLedger) if ((nType == TMNCreatedNode) || (nType == TMNModifiedNode)) { if (nType == TMNCreatedNode) // if created, thread to owner(s) - threadOwners(curNode, origLedger, newMod); + threadOwners(metaNode, curNode, origLedger, newMod); if (curNode->isThreadedType()) // always thread to self - threadNode(curNode, curNode, origLedger, newMod); + threadTx(metaNode, curNode, origLedger, newMod); if (nType == TMNModifiedNode) { diff --git a/src/LedgerEntrySet.h b/src/LedgerEntrySet.h index 6d77b35928..da66cda2d2 100644 --- a/src/LedgerEntrySet.h +++ b/src/LedgerEntrySet.h @@ -41,13 +41,13 @@ protected: SLE::pointer getForMod(const uint256& node, Ledger::pointer& ledger, boost::unordered_map& newMods); - bool threadNode(SLE::pointer& node, const NewcoinAddress& threadTo, Ledger::pointer& ledger, + bool threadTx(TransactionMetaNode& metaNode, const NewcoinAddress& threadTo, Ledger::pointer& ledger, boost::unordered_map& newMods); - bool threadNode(SLE::pointer& node, SLE::pointer& threadTo, Ledger::pointer& ledger, + bool threadTx(TransactionMetaNode& metaNode, SLE::pointer& threadTo, Ledger::pointer& ledger, boost::unordered_map& newMods); - bool threadOwners(SLE::pointer& node, Ledger::pointer& ledger, + bool threadOwners(TransactionMetaNode& metaNode, SLE::pointer& node, Ledger::pointer& ledger, boost::unordered_map& newMods); public: diff --git a/src/TransactionMeta.cpp b/src/TransactionMeta.cpp index d6c80d9add..d637710029 100644 --- a/src/TransactionMeta.cpp +++ b/src/TransactionMeta.cpp @@ -262,6 +262,14 @@ bool TransactionMetaSet::isNodeAffected(const uint256& node) const return mNodes.find(node) != mNodes.end(); } +TransactionMetaNode& TransactionMetaSet::getAffectedNode(const uint256& node, int type) +{ + std::map::iterator it = mNodes.find(node); + if (it != mNodes.end()) + return it->second; + return mNodes.insert(std::make_pair(node, TransactionMetaNode(node, type))).first->second; +} + const TransactionMetaNode& TransactionMetaSet::peekAffectedNode(const uint256& node) const { std::map::const_iterator it = mNodes.find(node); @@ -283,28 +291,3 @@ void TransactionMetaSet::swap(TransactionMetaSet& s) mNodes.swap(s.mNodes); } -TransactionMetaNode& TransactionMetaSet::modifyNode(const uint256& node) -{ - std::map::iterator it = mNodes.find(node); - if (it != mNodes.end()) - return it->second; - return mNodes.insert(std::make_pair(node, TransactionMetaNode(node))).first->second; -} - -#if 0 -void TransactionMetaSet::threadNode(const uint256& node, const uint256& prevTx, uint32 prevLgr) -{ - modifyNode(node).thread(prevTx, prevLgr); -} - -void TransactionMetaSet::deleteUnfunded(const uint256& nodeID, - const STAmount& firstBalance, const STAmount &secondBalance) -{ - TransactionMetaNode& node = modifyNode(nodeID); - TMNEUnfunded* entry = dynamic_cast(node.findEntry(TransactionMetaNodeEntry::TMNDeleteUnfunded)); - if (entry) - entry->setBalances(firstBalance, secondBalance); - else - node.addNode(new TMNEUnfunded(firstBalance, secondBalance)); -} -#endif diff --git a/src/TransactionMeta.h b/src/TransactionMeta.h index 4060353221..165db3c46b 100644 --- a/src/TransactionMeta.h +++ b/src/TransactionMeta.h @@ -133,7 +133,7 @@ protected: boost::ptr_vector mEntries; public: - TransactionMetaNode(const uint256 &node) : mNode(node) { ; } + TransactionMetaNode(const uint256 &node, int type) : mType(type), mNode(node) { ; } const uint256& getNode() const { return mNode; } const boost::ptr_vector& peekEntries() const { return mEntries; } @@ -163,8 +163,6 @@ protected: uint32 mLedger; std::map mNodes; - TransactionMetaNode& modifyNode(const uint256&); - public: TransactionMetaSet() : mLedger(0) { ; } TransactionMetaSet(const uint256& txID, uint32 ledger) : mTransactionID(txID), mLedger(ledger) { ; } @@ -174,6 +172,9 @@ public: void clear() { mNodes.clear(); } void swap(TransactionMetaSet&); + const uint256& getTxID() { return mTransactionID; } + uint32 getLgrSeq() { return mLedger; } + bool isNodeAffected(const uint256&) const; TransactionMetaNode& getAffectedNode(const uint256&, int type); const TransactionMetaNode& peekAffectedNode(const uint256&) const;