From 9d10cb419a2804a38c207d3ace9ee34aacbc3052 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Wed, 10 Oct 2012 11:25:11 -0700 Subject: [PATCH 01/21] Add Tom Wu BSD licensing for jsbn to LICENSE. --- LICENSE | Bin 774 -> 2321 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/LICENSE b/LICENSE index c15999ab1e9824bcb764613a9ccec2abb10c46c6..0388cedaed4a39cf59a509d846482cc7f7c469ca 100644 GIT binary patch literal 2321 zcmZ`*!FHQS5WMRv`uSw%DUzLidsv?qODJZ8Knuu9PI)63nTZiYW(F(Xuit7AitRWj zNi$7%Rdscvtdu13T<;rEKdJhjcB+z=+PaX29)(f5wUq1T$*B9%*~w^>mCDjVn+F`% zPN>>aV{~Jb6XpqLg`A95((IMBO4o#7Bfq!G$bxp-P@$|dYTG(oB3r8WvU})yG#jeW zd4543F0Ve2XI$ADxYW36NukPRZRMEmr0Mj#np{rkJe4oo#QC^W6b3UtO8u`_UoR)_ zha)J=-C`W2bItX1dN>>=TP`xu=6?Dr{^A!UZj{Tls^8Y&FV^6aQsJ~M6-DAf>@_;` zhF*{=V|sl$D&(WAbOTbqmtq-Y)6aO$4q{Y;7#8$dtmjTWNpOrB=s%;4dbQQ9$z{j= z7-*+^<=ziZHD&YMhP@p!SYp#&_g+82L3?xkDA~zB`?u3or4KwgrzyD}ji&EL^zLmB zUH(bb=jRZwswnA3ixO$2d6dNj=X~{Yh~PK5eWH6KYA1^^a6%Kkqr4R69)59}Fu}wM zW9sylCljbRk?1XfV8^q2;v?#Ugta)fPu2Lqw&}g1!#7wcjmFp=Il{kYn2GLhbldcKn)l zTPa(P8O>>jAlUNxab`ehiUF_^q9TdHBI`)Y(|nB~Qh`F81yTXUQ8CNa4<-7}fKHSk z*RC}+3PT`76dLk%MZd}19TV{r&uvf_in(Kt^o`8exm!5rr$wmN4yb!H+>{PXzcG(j zwiKYT?d0!81O!OVrvo`~ZMW9J5(@ojwCU=;COsG`yY(rJ7um*3dpVp!m}9L^xriu5lM4z>3#Imml`l6WE<`_w_cXU0FW>oD6)BaA@; z3a(k1xtDod1Gmbho!jl%<3En$pfC-dTqMdX zp|BGe)O0lRiUR8f?_JdS-eU1|6^y(WhL=vi@s0}u Date: Wed, 10 Oct 2012 12:44:00 -0700 Subject: [PATCH 02/21] Have RPCServer report messages from throws. --- src/RPCServer.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/RPCServer.cpp b/src/RPCServer.cpp index 0723e7936..ca1eb0dc1 100644 --- a/src/RPCServer.cpp +++ b/src/RPCServer.cpp @@ -2738,8 +2738,10 @@ Json::Value RPCServer::doCommand(const std::string& command, Json::Value& params try { return (this->*(commandsA[i].dfpFunc))(params); } - catch (...) + catch (std::exception& e) { + cLog(lsINFO) << "Caught throw: " << e.what(); + return RPCError(rpcINTERNAL); } } From 157dce46cfd77e0bc1f4b3e67c65b9e8e0b0682d Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Wed, 10 Oct 2012 15:05:31 -0700 Subject: [PATCH 03/21] Fix a problem with offer delivery. --- src/RippleCalc.cpp | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/src/RippleCalc.cpp b/src/RippleCalc.cpp index 817660d05..f8b8d5eee 100644 --- a/src/RippleCalc.cpp +++ b/src/RippleCalc.cpp @@ -478,6 +478,8 @@ TER RippleCalc::calcNodeDeliverFwd( const uint160& uPrvIssuerID = pnPrv.uIssuerID; const STAmount& saTransferRate = pnPrv.saTransferRate; + STAmount& saCurDeliverAct = pnCur.saFwdDeliver; + saInAct = 0; saInFees = 0; @@ -594,8 +596,11 @@ TER RippleCalc::calcNodeDeliverFwd( bEntryAdvance = true; } - saInAct += saInPassAct; - saInFees += saInPassFees; + saInAct += saInPassAct; + saInFees += saInPassFees; + + // Adjust amount available to next node. + saCurDeliverAct += saOutPassAct; } } @@ -1086,10 +1091,10 @@ TER RippleCalc::calcNodeAccountRev(const unsigned int uIndex, const PathState::p return terResult; } -// Perfrom balance adjustments between previous and current node. +// Perform balance adjustments between previous and current node. // - The previous node: specifies what to push through to current. // - All of previous output is consumed. -// Then, compute output for next node. +// Then, compute current node's output for next node. // - Current node: specify what to push through to next. // - Output to next node is computed as input minus quality or transfer fee. TER RippleCalc::calcNodeAccountFwd( @@ -1299,12 +1304,12 @@ TER RippleCalc::calcNodeAccountFwd( if (uIndex == uLast) { // offer --> ACCOUNT --> $ - cLog(lsINFO) << boost::str(boost::format("calcNodeAccountFwd: offer --> ACCOUNT --> $")); + cLog(lsINFO) << boost::str(boost::format("calcNodeAccountFwd: offer --> ACCOUNT --> $ : %s") % saPrvDeliverReq.getFullText()); STAmount& saCurReceive = pspCur->saOutAct; // Amount to credit. - saCurReceive = saPrvDeliverAct; + saCurReceive = saPrvDeliverReq; // No income balance adjustments necessary. The paying side inside the offer paid to this account. } @@ -1797,6 +1802,14 @@ void RippleCalc::pathNext(const PathState::pointer& pspCur, const int iPaths, co pspCur->terStatus = calcNodeFwd(0, pspCur, bMultiQuality); + tLog(tesSUCCESS == pspCur->terStatus, lsDEBUG) + << boost::str(boost::format("saOutAct=%s saInAct=%s") + % pspCur->saOutAct.getFullText() + % pspCur->saInAct.getFullText()); + + // Make sure we have a quality. + assert(tesSUCCESS != pspCur->terStatus || (!!pspCur->saOutAct && !!pspCur->saInAct)); + pspCur->uQuality = tesSUCCESS == pspCur->terStatus ? STAmount::getRate(pspCur->saOutAct, pspCur->saInAct) // Calculate relative quality. : 0; // Mark path as inactive. @@ -1928,6 +1941,7 @@ TER RippleCalc::rippleCalc( // Find the best path. BOOST_FOREACH(PathState::pointer& pspCur, vpsPaths) { + // XXX Handle paths that are found dry? rc.pathNext(pspCur, vpsPaths.size(), lesCheckpoint, lesActive); // Compute increment. if ((!bLimitQuality || pspCur->uQuality <= uQualityLimit) // Quality is not limted or increment has allowed quality. From 5f28af66ca64f07c14672e8862987a75cb240804 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Wed, 10 Oct 2012 20:12:18 -0700 Subject: [PATCH 04/21] Fix error checking in RippleCalc. --- src/RippleCalc.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/RippleCalc.cpp b/src/RippleCalc.cpp index f8b8d5eee..58673dd58 100644 --- a/src/RippleCalc.cpp +++ b/src/RippleCalc.cpp @@ -861,18 +861,19 @@ TER RippleCalc::calcNodeAccountRev(const unsigned int uIndex, const PathState::p const STAmount& saCurDeliverReq = pnCur.saRevDeliver; STAmount saCurDeliverAct(saCurDeliverReq.getCurrency(), saCurDeliverReq.getIssuer()); - cLog(lsINFO) << boost::str(boost::format("calcNodeAccountRev: saPrvRedeemReq=%s saPrvIssueReq=%s saCurRedeemReq=%s saNxtOwed=%s") + cLog(lsINFO) << boost::str(boost::format("calcNodeAccountRev: saPrvRedeemReq=%s saPrvIssueReq=%s saCurRedeemReq=%s saCurIssueReq=%s saNxtOwed=%s") % saPrvRedeemReq.getFullText() % saPrvIssueReq.getFullText() % saCurRedeemReq.getFullText() + % saCurIssueReq.getFullText() % saNxtOwed.getFullText()); cLog(lsINFO) << pspCur->getJson(); assert(!saCurRedeemReq || (-saNxtOwed) >= saCurRedeemReq); // Current redeem req can't be more than IOUs on hand. assert(!saCurIssueReq // If not issuing, fine. - || !saNxtOwed.isNegative() // Not hold next IOUs: owed is >= 0 - || saNxtOwed == saCurRedeemReq); // If issue req, then redeem req must consume all owed. + || !saNxtOwed.isNegative() // saNxtOwed >= 0: Sender not holding next IOUs, saNxtOwed < 0: Sender holding next IOUs. + || -saNxtOwed == saCurRedeemReq); // If issue req, then redeem req must consume all owed. if (bPrvAccount && bNxtAccount) { From d086c05966ae02d59ed90283eb558aa0bebb88a8 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Wed, 10 Oct 2012 20:50:17 -0700 Subject: [PATCH 05/21] Fix ripple balance handling between path increments. --- src/RippleCalc.cpp | 60 +++++++++++++++++++++++++++++++++------------- 1 file changed, 44 insertions(+), 16 deletions(-) diff --git a/src/RippleCalc.cpp b/src/RippleCalc.cpp index 58673dd58..f284c57c3 100644 --- a/src/RippleCalc.cpp +++ b/src/RippleCalc.cpp @@ -1566,6 +1566,7 @@ PathState::PathState( saInReq = saSendMax; saOutReq = saSend; + uQuality = 1; // Mark path as active. // Push sending node. terStatus = pushNode( @@ -1927,8 +1928,8 @@ TER RippleCalc::rippleCalc( terResult = temUNCERTAIN; } - STAmount saPaid; - STAmount saWanted; + STAmount saInAct; + STAmount saOutAct; const LedgerEntrySet lesBase = lesActive; // Checkpoint with just fees paid. const uint64 uQualityLimit = bLimitQuality ? STAmount::getRate(saDstAmountReq, saMaxAmountReq) : 0; // When processing, don't want to complicate directory walking with deletion. @@ -1942,16 +1943,26 @@ TER RippleCalc::rippleCalc( // Find the best path. BOOST_FOREACH(PathState::pointer& pspCur, vpsPaths) { - // XXX Handle paths that are found dry? - rc.pathNext(pspCur, vpsPaths.size(), lesCheckpoint, lesActive); // Compute increment. + if (pspCur->uQuality) + { + pspCur->saInAct = saInAct; // Update to current amount processed. + pspCur->saOutAct = saOutAct; - if ((!bLimitQuality || pspCur->uQuality <= uQualityLimit) // Quality is not limted or increment has allowed quality. - || !pspBest // Best is not yet set. - || (pspCur->uQuality && PathState::lessPriority(pspBest, pspCur))) // Current is better than set. - { - lesActive.swapWith(pspCur->lesEntries); // For the path, save ledger state. - pspBest = pspCur; - } + rc.pathNext(pspCur, vpsPaths.size(), lesCheckpoint, lesActive); // Compute increment. + + if (!pspCur->uQuality) { + // Path was dry. + + nothing(); + } + else if ((!bLimitQuality || pspCur->uQuality <= uQualityLimit) // Quality is not limted or increment has allowed quality. + || !pspBest // Best is not yet set. + || PathState::lessPriority(pspBest, pspCur)) // Current is better than set. + { + lesActive.swapWith(pspCur->lesEntries); // For the path, save ledger state. + pspBest = pspCur; + } + } } if (pspBest) @@ -1964,18 +1975,35 @@ TER RippleCalc::rippleCalc( // Record best pass' LedgerEntrySet to build off of and potentially return. lesActive.swapWith(pspBest->lesEntries); - // Figure out if done. - if (temUNCERTAIN == terResult && saPaid == saWanted) + saInAct += pspBest->saInAct; + saOutAct += pspBest->saOutAct; + + if (temUNCERTAIN == terResult && saOutAct == saDstAmountReq) { + // Done. Delivered requested amount. + terResult = tesSUCCESS; } - else + else if (saInAct != saMaxAmountReq) { - // Prepare for next pass. + // Have not met requested amount or max send. Prepare for next pass. // Merge best pass' umReverse. rc.mumSource.insert(pspBest->umReverse.begin(), pspBest->umReverse.end()); } + else if (!bPartialPayment) + { + // Have sent maximum allowed. Partial payment not allowed. + + terResult = tepPATH_PARTIAL; + lesActive = lesBase; // Revert to just fees charged. + } + else + { + // Have sent maximum allowed. Partial payment allowed. Success. + + terResult = tesSUCCESS; + } } // Not done and ran out of paths. else if (!bPartialPayment) @@ -1985,7 +2013,7 @@ TER RippleCalc::rippleCalc( lesActive = lesBase; // Revert to just fees charged. } // Partial payment ok. - else if (!saPaid) + else if (!saOutAct) { // No payment at all. terResult = tepPATH_DRY; From dfff2c61d1b4a812d75e2f817e0d5c6aa4407345 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Wed, 10 Oct 2012 22:12:56 -0700 Subject: [PATCH 06/21] Transaction engine makes sure max send is positive. --- src/TransactionAction.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/TransactionAction.cpp b/src/TransactionAction.cpp index 35ed8397d..619a932bc 100644 --- a/src/TransactionAction.cpp +++ b/src/TransactionAction.cpp @@ -504,9 +504,15 @@ TER TransactionEngine::doPayment(const SerializedTransaction& txn, const Transac return temDST_NEEDED; } + else if (bMax && !saMaxAmount.isPositive()) + { + Log(lsINFO) << "doPayment: Invalid transaction: bad max amount: " << saMaxAmount.getFullText(); + + return temBAD_AMOUNT; + } else if (!saDstAmount.isPositive()) { - Log(lsINFO) << "doPayment: Invalid transaction: bad amount: " << saDstAmount.getHumanCurrency() << " " << saDstAmount.getText(); + Log(lsINFO) << "doPayment: Invalid transaction: bad dst amount: " << saDstAmount.getFullText(); return temBAD_AMOUNT; } From f81a3c623a7c48fceb95dee0685e90b83eae38fb Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Wed, 10 Oct 2012 22:13:39 -0700 Subject: [PATCH 07/21] More fixes for ripple incremental pass handling. --- src/RippleCalc.cpp | 95 ++++++++++++++++++++++++++-------------------- src/RippleCalc.h | 10 +++-- 2 files changed, 60 insertions(+), 45 deletions(-) diff --git a/src/RippleCalc.cpp b/src/RippleCalc.cpp index f284c57c3..2de815e3d 100644 --- a/src/RippleCalc.cpp +++ b/src/RippleCalc.cpp @@ -888,8 +888,8 @@ TER RippleCalc::calcNodeAccountRev(const unsigned int uIndex, const PathState::p // account --> ACCOUNT --> $ // Overall deliverable. const STAmount& saCurWantedReq = bPrvAccount - ? std::min(pspCur->saOutReq, saPrvLimit+saPrvOwed) // If previous is an account, limit. - : pspCur->saOutReq; // Previous is an offer, no limit: redeem own IOUs. + ? std::min(pspCur->saOutReq-pspCur->saOutAct, saPrvLimit+saPrvOwed) // If previous is an account, limit. + : pspCur->saOutReq-pspCur->saOutAct; // Previous is an offer, no limit: redeem own IOUs. STAmount saCurWantedAct(saCurWantedReq.getCurrency(), saCurWantedReq.getIssuer()); cLog(lsINFO) << boost::str(boost::format("calcNodeAccountRev: account --> ACCOUNT --> $ : saCurWantedReq=%s") @@ -1023,8 +1023,8 @@ TER RippleCalc::calcNodeAccountRev(const unsigned int uIndex, const PathState::p { // offer --> ACCOUNT --> $ const STAmount& saCurWantedReq = bPrvAccount - ? std::min(pspCur->saOutReq, saPrvLimit+saPrvOwed) // If previous is an account, limit. - : pspCur->saOutReq; // Previous is an offer, no limit: redeem own IOUs. + ? std::min(pspCur->saOutReq-pspCur->saOutAct, saPrvLimit+saPrvOwed) // If previous is an account, limit. + : pspCur->saOutReq-pspCur->saOutAct; // Previous is an offer, no limit: redeem own IOUs. STAmount saCurWantedAct(saCurWantedReq.getCurrency(), saCurWantedReq.getIssuer()); cLog(lsINFO) << boost::str(boost::format("calcNodeAccountRev: offer --> ACCOUNT --> $ : saCurWantedReq=%s") @@ -1165,16 +1165,12 @@ TER RippleCalc::calcNodeAccountFwd( // ^ --> ACCOUNT --> account // First node, calculate amount to send. - // XXX Use stamp/ripple balance - PaymentNode& pnCur = pspCur->vpnNodes[uIndex]; + // XXX Limit by stamp/ripple balance - const STAmount& saCurRedeemReq = pnCur.saRevRedeem; - STAmount& saCurRedeemAct = pnCur.saFwdRedeem; - const STAmount& saCurIssueReq = pnCur.saRevIssue; - STAmount& saCurIssueAct = pnCur.saFwdIssue; - - const STAmount& saCurSendMaxReq = pspCur->saInReq; // Negative for no limit, doing a calculation. - STAmount& saCurSendMaxAct = pspCur->saInAct; // Report to user how much this sends. + const STAmount& saCurSendMaxReq = pspCur->saInReq.isNegative() + ? pspCur->saInReq // Negative for no limit, doing a calculation. + : pspCur->saInReq-pspCur->saInAct; // request - done. + STAmount& saCurSendMaxPass = pspCur->saInPass; // Report how much pass sends. if (saCurRedeemReq) { @@ -1185,28 +1181,35 @@ TER RippleCalc::calcNodeAccountFwd( } else { - saCurRedeemAct = STAmount(saCurRedeemReq); - } - saCurSendMaxAct = saCurRedeemAct; + // No redeeming. - if (saCurIssueReq && (saCurSendMaxReq.isNegative() || saCurSendMaxReq != saCurRedeemAct)) + saCurRedeemAct = saCurRedeemReq; + } + saCurSendMaxPass = saCurRedeemAct; + + if (saCurIssueReq && (saCurSendMaxReq.isNegative() || saCurSendMaxPass != saCurSendMaxReq)) { - // Issue requested and not over budget. + // Issue requested and pass does not meet max. saCurIssueAct = saCurSendMaxReq.isNegative() ? saCurIssueReq : std::min(saCurSendMaxReq-saCurRedeemAct, saCurIssueReq); } else { + // No issuing. + saCurIssueAct = STAmount(saCurIssueReq); } - saCurSendMaxAct += saCurIssueAct; + saCurSendMaxPass += saCurIssueAct; - cLog(lsINFO) << boost::str(boost::format("calcNodeAccountFwd: ^ --> ACCOUNT --> account : saCurSendMaxReq=%s saCurRedeemAct=%s saCurIssueReq=%s saCurIssueAct=%s") + cLog(lsINFO) << boost::str(boost::format("calcNodeAccountFwd: ^ --> ACCOUNT --> account : saInReq=%s saInAct=%s saCurSendMaxReq=%s saCurRedeemAct=%s saCurIssueReq=%s saCurIssueAct=%s saCurSendMaxPass=%s") + % pspCur->saInReq.getFullText() + % pspCur->saInAct.getFullText() % saCurSendMaxReq.getFullText() % saCurRedeemAct.getFullText() % saCurIssueReq.getFullText() - % saCurIssueAct.getFullText()); + % saCurIssueAct.getFullText() + % saCurSendMaxPass.getFullText()); } else if (uIndex == uLast) { @@ -1219,7 +1222,7 @@ TER RippleCalc::calcNodeAccountFwd( // Last node. Accept all funds. Calculate amount actually to credit. - STAmount& saCurReceive = pspCur->saOutAct; + STAmount& saCurReceive = pspCur->saOutPass; STAmount saIssueCrd = uQualityIn >= QUALITY_ONE ? saPrvIssueReq // No fee. @@ -1307,7 +1310,7 @@ TER RippleCalc::calcNodeAccountFwd( // offer --> ACCOUNT --> $ cLog(lsINFO) << boost::str(boost::format("calcNodeAccountFwd: offer --> ACCOUNT --> $ : %s") % saPrvDeliverReq.getFullText()); - STAmount& saCurReceive = pspCur->saOutAct; + STAmount& saCurReceive = pspCur->saOutPass; // Amount to credit. saCurReceive = saPrvDeliverReq; @@ -1365,8 +1368,8 @@ bool PathState::lessPriority(const PathState::pointer& lhs, const PathState::poi return lhs->uQuality > rhs->uQuality; // Bigger is worse. // Best quanity is second rank. - if (lhs->saOutAct != rhs->saOutAct) - return lhs->saOutAct < rhs->saOutAct; // Smaller is worse. + if (lhs->saOutPass != rhs->saOutPass) + return lhs->saOutPass < rhs->saOutPass; // Smaller is worse. // Path index is third rank. return lhs->mIndex > rhs->mIndex; // Bigger is worse. @@ -1555,7 +1558,11 @@ PathState::PathState( const STAmount& saSend, const STAmount& saSendMax ) - : mLedger(lesSource.getLedgerRef()), mIndex(iIndex), uQuality(0) + : mLedger(lesSource.getLedgerRef()), + mIndex(iIndex), + uQuality(1), // Mark path as active. + saInReq(saSendMax), + saOutReq(saSend) { const uint160 uInCurrencyID = saSendMax.getCurrency(); const uint160 uOutCurrencyID = saSend.getCurrency(); @@ -1564,10 +1571,6 @@ PathState::PathState( lesEntries = lesSource.duplicate(); - saInReq = saSendMax; - saOutReq = saSend; - uQuality = 1; // Mark path as active. - // Push sending node. terStatus = pushNode( STPathElement::typeAccount @@ -1691,12 +1694,18 @@ Json::Value PathState::getJson() const if (saInAct) jvPathState["in_act"] = saInAct.getJson(0); + if (saInPass) + jvPathState["in_pass"] = saInPass.getJson(0); + if (saOutReq) jvPathState["out_req"] = saOutReq.getJson(0); if (saOutAct) jvPathState["out_act"] = saOutAct.getJson(0); + if (saOutPass) + jvPathState["out_pass"] = saOutPass.getJson(0); + if (uQuality) jvPathState["uQuality"] = Json::Value::UInt(uQuality); @@ -1782,13 +1791,17 @@ void RippleCalc::pathNext(const PathState::pointer& pspCur, const int iPaths, co const bool bMultiQuality = iPaths == 1; const unsigned int uLast = pspCur->vpnNodes.size() - 1; - cLog(lsINFO) << "Path In: " << pspCur->getJson(); - - assert(pspCur->vpnNodes.size() >= 2); + // YYY This clearing should only be needed for nice logging. + pspCur->saInPass = STAmount(pspCur->saInReq.getCurrency(), pspCur->saInReq.getIssuer()); + pspCur->saOutPass = STAmount(pspCur->saOutReq.getCurrency(), pspCur->saOutReq.getIssuer()); pspCur->vUnfundedBecame.clear(); pspCur->umReverse.clear(); + cLog(lsINFO) << "Path In: " << pspCur->getJson(); + + assert(pspCur->vpnNodes.size() >= 2); + lesCurrent = lesCheckpoint; // Restore from checkpoint. lesCurrent.bumpSeq(); // Begin ledger varance. @@ -1805,16 +1818,16 @@ void RippleCalc::pathNext(const PathState::pointer& pspCur, const int iPaths, co pspCur->terStatus = calcNodeFwd(0, pspCur, bMultiQuality); tLog(tesSUCCESS == pspCur->terStatus, lsDEBUG) - << boost::str(boost::format("saOutAct=%s saInAct=%s") - % pspCur->saOutAct.getFullText() - % pspCur->saInAct.getFullText()); + << boost::str(boost::format("saOutPass=%s saInPass=%s") + % pspCur->saOutPass.getFullText() + % pspCur->saInPass.getFullText()); // Make sure we have a quality. - assert(tesSUCCESS != pspCur->terStatus || (!!pspCur->saOutAct && !!pspCur->saInAct)); + assert(tesSUCCESS != pspCur->terStatus || (!!pspCur->saOutPass && !!pspCur->saInPass)); pspCur->uQuality = tesSUCCESS == pspCur->terStatus - ? STAmount::getRate(pspCur->saOutAct, pspCur->saInAct) // Calculate relative quality. - : 0; // Mark path as inactive. + ? STAmount::getRate(pspCur->saOutPass, pspCur->saInPass) // Calculate relative quality. + : 0; // Mark path as inactive. cLog(lsINFO) << "Path after forward: " << pspCur->getJson(); } @@ -1975,8 +1988,8 @@ TER RippleCalc::rippleCalc( // Record best pass' LedgerEntrySet to build off of and potentially return. lesActive.swapWith(pspBest->lesEntries); - saInAct += pspBest->saInAct; - saOutAct += pspBest->saOutAct; + saInAct += pspBest->saInPass; + saOutAct += pspBest->saOutPass; if (temUNCERTAIN == terResult && saOutAct == saDstAmountReq) { diff --git a/src/RippleCalc.h b/src/RippleCalc.h index 673393b5d..14d07f4aa 100644 --- a/src/RippleCalc.h +++ b/src/RippleCalc.h @@ -91,10 +91,12 @@ public: int mIndex; uint64 uQuality; // 0 = none. - STAmount saInReq; // Max amount to spend by sender - STAmount saInAct; // Amount spent by sender (calc output) - STAmount saOutReq; // Amount to send (calc input) - STAmount saOutAct; // Amount actually sent (calc output). + const STAmount& saInReq; // --> Max amount to spend by sender. + STAmount saInAct; // --> Amount spent by sender so far. + STAmount saInPass; // <-- Amount spent by sender. + const STAmount& saOutReq; // --> Amount to send. + STAmount saOutAct; // --> Amount actually sent so far. + STAmount saOutPass; // <-- Amount actually sent. PathState( const int iIndex, From 30dd46d8124bffdf2219919f5db8d4cf8e2b909d Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Thu, 11 Oct 2012 02:50:04 -0700 Subject: [PATCH 08/21] Improve SHAMapMissingNode --- src/SHAMap.cpp | 18 ++++++++++++------ src/SHAMap.h | 14 ++++++++++++-- src/SHAMapSync.cpp | 7 ++++--- 3 files changed, 28 insertions(+), 11 deletions(-) diff --git a/src/SHAMap.cpp b/src/SHAMap.cpp index 5dd31f565..533b9d671 100644 --- a/src/SHAMap.cpp +++ b/src/SHAMap.cpp @@ -93,7 +93,8 @@ std::stack SHAMap::getStack(const uint256& id, bool inc { if (partialOk) return stack; - throw mn; + mn.setTargetNode(id); + throw; } } @@ -153,10 +154,15 @@ SHAMapTreeNode::pointer SHAMap::walkTo(const uint256& id, bool modify) return inNode; uint256 childHash = inNode->getChildHash(branch); - SHAMapTreeNode::pointer nextNode = getNode(inNode->getChildNodeID(branch), childHash, false); - if (!nextNode) - throw SHAMapMissingNode(inNode->getChildNodeID(branch), childHash); - inNode = nextNode; + try + { + inNode = getNode(inNode->getChildNodeID(branch), childHash, false); + } + catch (SHAMapMissingNode& mn) + { + mn.setTargetNode(id); + throw; + } } if (inNode->getTag() != id) return SHAMapTreeNode::pointer(); @@ -175,7 +181,7 @@ SHAMapTreeNode* SHAMap::walkToPointer(const uint256& id) if (nextHash.isZero()) return NULL; inNode = getNodePointer(inNode->getChildNodeID(branch), nextHash); if (!inNode) - throw SHAMapMissingNode(inNode->getChildNodeID(branch), nextHash); + throw SHAMapMissingNode(inNode->getChildNodeID(branch), nextHash, id); } return (inNode->getTag() == id) ? inNode : NULL; } diff --git a/src/SHAMap.h b/src/SHAMap.h index c239bad30..a942943b1 100644 --- a/src/SHAMap.h +++ b/src/SHAMap.h @@ -241,16 +241,26 @@ class SHAMapMissingNode : public std::runtime_error protected: SHAMapNode mNodeID; uint256 mNodeHash; + uint256 mTargetIndex; public: SHAMapMissingNode(const SHAMapNode& nodeID, const uint256& nodeHash) : std::runtime_error(nodeID.getString()), mNodeID(nodeID), mNodeHash(nodeHash) { ; } + + SHAMapMissingNode(const SHAMapNode& nodeID, const uint256& nodeHash, const uint256& targetIndex) : + std::runtime_error(nodeID.getString()), mNodeID(nodeID), mNodeHash(nodeHash), mTargetIndex(targetIndex) + { ; } + virtual ~SHAMapMissingNode() throw() { ; } - const SHAMapNode& getNodeID() const { return mNodeID; } - const uint256& getNodeHash() const { return mNodeHash; } + void setTargetNode(const uint256& tn) { mTargetIndex = tn; } + + const SHAMapNode& getNodeID() const { return mNodeID; } + const uint256& getNodeHash() const { return mNodeHash; } + const uint256& getTargetIndex() const { return mTargetIndex; } + bool hasTargetIndex() const { return !mTargetIndex.isZero(); } }; class SHAMap diff --git a/src/SHAMapSync.cpp b/src/SHAMapSync.cpp index fef3cf04a..baf7de950 100644 --- a/src/SHAMapSync.cpp +++ b/src/SHAMapSync.cpp @@ -53,7 +53,7 @@ void SHAMap::getMissingNodes(std::vector& nodeIDs, std::vectorisInner() && !nextNode->isFullBelow()) return true; } - catch (SHAMapMissingNode) + catch (SHAMapMissingNode&) { return true; } } iNode->setFullBelow(); } while (!stack.empty()); - if (root->isFullBelow()) clearSynching(); + if (root->isFullBelow()) + clearSynching(); return true; } From 67477beecb484d35ef8a3bc33d542310bdd78b02 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Thu, 11 Oct 2012 03:13:28 -0700 Subject: [PATCH 09/21] Track the type of map in the SHAMap. This will make it easier to parse missing nodes at ledger level. --- src/Ledger.cpp | 8 ++++---- src/LedgerConsensus.cpp | 4 ++-- src/SHAMap.cpp | 8 ++++---- src/SHAMap.h | 13 +++++++++++-- src/SHAMapSync.cpp | 2 +- 5 files changed, 22 insertions(+), 13 deletions(-) diff --git a/src/Ledger.cpp b/src/Ledger.cpp index f52e1f1e7..35ffc7dcf 100644 --- a/src/Ledger.cpp +++ b/src/Ledger.cpp @@ -24,7 +24,7 @@ SETUP_LOG(); Ledger::Ledger(const NewcoinAddress& masterID, uint64 startAmount) : mTotCoins(startAmount), mLedgerSeq(1), mCloseTime(0), mParentCloseTime(0), mCloseResolution(LEDGER_TIME_ACCURACY), mCloseFlags(0), mClosed(false), mValidHash(false), mAccepted(false), mImmutable(false), - mTransactionMap(new SHAMap()), mAccountStateMap(new SHAMap()) + mTransactionMap(new SHAMap(smtTRANSACTION)), mAccountStateMap(new SHAMap(smtFREE)) { // special case: put coins in root account AccountState::pointer startAccount = boost::make_shared(masterID); @@ -62,7 +62,7 @@ Ledger::Ledger(bool /* dummy */, Ledger& prevLedger) : mTotCoins(prevLedger.mTotCoins), mLedgerSeq(prevLedger.mLedgerSeq + 1), mParentCloseTime(prevLedger.mCloseTime), mCloseResolution(prevLedger.mCloseResolution), mCloseFlags(0), mClosed(false), mValidHash(false), mAccepted(false), mImmutable(false), - mTransactionMap(new SHAMap()), mAccountStateMap(prevLedger.mAccountStateMap->snapShot(true)) + mTransactionMap(new SHAMap(smtTRANSACTION)), mAccountStateMap(prevLedger.mAccountStateMap->snapShot(true)) { // Create a new ledger that follows this one prevLedger.updateHash(); mParentHash = prevLedger.getHash(); @@ -123,8 +123,8 @@ void Ledger::setRaw(const Serializer &s) updateHash(); if(mValidHash) { - mTransactionMap = boost::make_shared(mTransHash); - mAccountStateMap = boost::make_shared(mAccountHash); + mTransactionMap = boost::make_shared(smtTRANSACTION, mTransHash); + mAccountStateMap = boost::make_shared(smtSTATE, mAccountHash); } } diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index a07965ae6..c915faad7 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -27,7 +27,7 @@ SETUP_LOG(); TransactionAcquire::TransactionAcquire(const uint256& hash) : PeerSet(hash, TX_ACQUIRE_TIMEOUT), mHaveRoot(false) { - mMap = boost::make_shared(hash); + mMap = boost::make_shared(smtTRANSACTION, hash); } void TransactionAcquire::done() @@ -759,7 +759,7 @@ SHAMap::pointer LedgerConsensus::getTransactionTree(const uint256& hash, bool do { if (!hash) { - SHAMap::pointer empty = boost::make_shared(); + SHAMap::pointer empty = boost::make_shared(smtTRANSACTION); mapComplete(hash, empty, false); return empty; } diff --git a/src/SHAMap.cpp b/src/SHAMap.cpp index 533b9d671..97580186e 100644 --- a/src/SHAMap.cpp +++ b/src/SHAMap.cpp @@ -41,14 +41,14 @@ std::size_t hash_value(const uint160& u) } -SHAMap::SHAMap(uint32 seq) : mSeq(seq), mState(smsModifying) +SHAMap::SHAMap(SHAMapType t, uint32 seq) : mSeq(seq), mState(smsModifying), mType(t) { root = boost::make_shared(mSeq, SHAMapNode(0, uint256())); root->makeInner(); mTNByID[*root] = root; } -SHAMap::SHAMap(const uint256& hash) : mSeq(0), mState(smsSynching) +SHAMap::SHAMap(SHAMapType t, const uint256& hash) : mSeq(0), mState(smsSynching), mType(t) { // FIXME: Need to acquire root node root = boost::make_shared(mSeq, SHAMapNode(0, uint256())); root->makeInner(); @@ -58,7 +58,7 @@ SHAMap::SHAMap(const uint256& hash) : mSeq(0), mState(smsSynching) SHAMap::pointer SHAMap::snapShot(bool isMutable) { // Return a new SHAMap that is an immutable snapshot of this one // Initially nodes are shared, but CoW is forced on both ledgers - SHAMap::pointer ret = boost::make_shared(); + SHAMap::pointer ret = boost::make_shared(mType); SHAMap& newMap = *ret; newMap.mSeq = ++mSeq; newMap.mTNByID = mTNByID; @@ -808,7 +808,7 @@ BOOST_AUTO_TEST_CASE( SHAMap_test ) h4.SetHex("b92891fe4ef6cee585fdc6fda2e09eb4d386363158ec3321b8123e5a772c6ca8"); h5.SetHex("a92891fe4ef6cee585fdc6fda0e09eb4d386363158ec3321b8123e5a772c6ca7"); - SHAMap sMap; + SHAMap sMap(smtFREE); SHAMapItem i1(h1, IntToVUC(1)), i2(h2, IntToVUC(2)), i3(h3, IntToVUC(3)), i4(h4, IntToVUC(4)), i5(h5, IntToVUC(5)); if (!sMap.addItem(i2, true, false)) BOOST_FAIL("no add"); diff --git a/src/SHAMap.h b/src/SHAMap.h index a942943b1..11c34a74d 100644 --- a/src/SHAMap.h +++ b/src/SHAMap.h @@ -128,6 +128,13 @@ enum SHANodeFormat snfWIRE = 2, // Compressed form used on the wire }; +enum SHAMapType +{ + smtTRANSACTION =1, // A tree of transactions + smtSTATE =2, // A tree of state nodes + smtFREE =3, // A tree not part of a ledger +}; + class SHAMapTreeNode : public SHAMapNode { friend class SHAMap; @@ -282,6 +289,8 @@ private: SHAMapState mState; + SHAMapType mType; + protected: void dirtyUp(std::stack& stack, const uint256& target, uint256 prevHash); @@ -306,8 +315,8 @@ protected: public: // build new map - SHAMap(uint32 seq = 0); - SHAMap(const uint256& hash); + SHAMap(SHAMapType t, uint32 seq = 0); + SHAMap(SHAMapType t, const uint256& hash); ~SHAMap() { mState = smsInvalid; } diff --git a/src/SHAMapSync.cpp b/src/SHAMapSync.cpp index baf7de950..7fdfac494 100644 --- a/src/SHAMapSync.cpp +++ b/src/SHAMapSync.cpp @@ -421,7 +421,7 @@ BOOST_AUTO_TEST_CASE( SHAMapSync_test ) srand(seed); cLog(lsTRACE) << "Constructing maps"; - SHAMap source, destination; + SHAMap source(smtFREE), destination(smtFREE); // add random data to the source map cLog(lsTRACE) << "Adding random data"; From 4f1ebc28840f19a4465ce09969285543a4173e9e Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Thu, 11 Oct 2012 03:16:18 -0700 Subject: [PATCH 10/21] Put the missing node type in the SHAMapMissingNode exception. --- src/SHAMap.cpp | 8 ++++---- src/SHAMap.h | 11 +++++++---- src/SHAMapDiff.cpp | 2 +- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/SHAMap.cpp b/src/SHAMap.cpp index 97580186e..efd97e266 100644 --- a/src/SHAMap.cpp +++ b/src/SHAMap.cpp @@ -181,7 +181,7 @@ SHAMapTreeNode* SHAMap::walkToPointer(const uint256& id) if (nextHash.isZero()) return NULL; inNode = getNodePointer(inNode->getChildNodeID(branch), nextHash); if (!inNode) - throw SHAMapMissingNode(inNode->getChildNodeID(branch), nextHash, id); + throw SHAMapMissingNode(mType, inNode->getChildNodeID(branch), nextHash, id); } return (inNode->getTag() == id) ? inNode : NULL; } @@ -686,11 +686,11 @@ void SHAMapItem::dump() SHAMapTreeNode::pointer SHAMap::fetchNodeExternal(const SHAMapNode& id, const uint256& hash) { if (!theApp->running()) - throw SHAMapMissingNode(id, hash); + throw SHAMapMissingNode(mType, id, hash); HashedObject::pointer obj(theApp->getHashedObjectStore().retrieve(hash)); if (!obj) - throw SHAMapMissingNode(id, hash); + throw SHAMapMissingNode(mType, id, hash); assert(Serializer::getSHA512Half(obj->getData()) == hash); try @@ -704,7 +704,7 @@ SHAMapTreeNode::pointer SHAMap::fetchNodeExternal(const SHAMapNode& id, const ui catch (...) { cLog(lsWARNING) << "fetchNodeExternal gets an invalid node: " << hash; - throw SHAMapMissingNode(id, hash); + throw SHAMapMissingNode(mType, id, hash); } } diff --git a/src/SHAMap.h b/src/SHAMap.h index 11c34a74d..72a4f23c3 100644 --- a/src/SHAMap.h +++ b/src/SHAMap.h @@ -246,17 +246,19 @@ public: class SHAMapMissingNode : public std::runtime_error { protected: + SHAMapType mType; SHAMapNode mNodeID; uint256 mNodeHash; uint256 mTargetIndex; public: - SHAMapMissingNode(const SHAMapNode& nodeID, const uint256& nodeHash) : - std::runtime_error(nodeID.getString()), mNodeID(nodeID), mNodeHash(nodeHash) + SHAMapMissingNode(SHAMapType t, const SHAMapNode& nodeID, const uint256& nodeHash) : + std::runtime_error(nodeID.getString()), mType(t), mNodeID(nodeID), mNodeHash(nodeHash) { ; } - SHAMapMissingNode(const SHAMapNode& nodeID, const uint256& nodeHash, const uint256& targetIndex) : - std::runtime_error(nodeID.getString()), mNodeID(nodeID), mNodeHash(nodeHash), mTargetIndex(targetIndex) + SHAMapMissingNode(SHAMapType t, const SHAMapNode& nodeID, const uint256& nodeHash, const uint256& targetIndex) : + std::runtime_error(nodeID.getString()), mType(t), + mNodeID(nodeID), mNodeHash(nodeHash), mTargetIndex(targetIndex) { ; } virtual ~SHAMapMissingNode() throw() @@ -264,6 +266,7 @@ public: void setTargetNode(const uint256& tn) { mTargetIndex = tn; } + SHAMapType getMapType() const { return mType; } const SHAMapNode& getNodeID() const { return mNodeID; } const uint256& getNodeHash() const { return mNodeHash; } const uint256& getTargetIndex() const { return mTargetIndex; } diff --git a/src/SHAMapDiff.cpp b/src/SHAMapDiff.cpp index fa1ae6a64..d0e78e8f9 100644 --- a/src/SHAMapDiff.cpp +++ b/src/SHAMapDiff.cpp @@ -120,7 +120,7 @@ bool SHAMap::compare(SHAMap::ref otherMap, SHAMapDiff& differences, int maxCount if (!ourNode || !otherNode) { assert(false); - throw SHAMapMissingNode(dNode.mNodeID, uint256()); + throw SHAMapMissingNode(mType, dNode.mNodeID, uint256()); } if (ourNode->isLeaf() && otherNode->isLeaf()) From c43934ab6f2d329386c15042c5865c915e502c3f Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Thu, 11 Oct 2012 05:06:24 -0700 Subject: [PATCH 11/21] Fix lots of places I used 'empty' instead of 'clear'. This is why I like 'isEmpty'. --- src/Application.cpp | 2 +- src/LedgerAcquire.cpp | 2 +- src/PubKeyCache.cpp | 2 +- src/SerializedObject.cpp | 8 ++++---- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/Application.cpp b/src/Application.cpp index a5d458dc1..fa8861fa1 100644 --- a/src/Application.cpp +++ b/src/Application.cpp @@ -215,8 +215,8 @@ void Application::loadOldLedger() std::cout << "No Ledger found?" << std::endl; exit(-1); } - lastLedger->setClosed(); + Ledger::pointer openLedger = boost::make_shared(false, boost::ref(*lastLedger)); mMasterLedger.switchLedgers(lastLedger, openLedger); mNetOps.setLastCloseTime(lastLedger->getCloseTimeNC()); diff --git a/src/LedgerAcquire.cpp b/src/LedgerAcquire.cpp index d9056fdad..1eac7dc3f 100644 --- a/src/LedgerAcquire.cpp +++ b/src/LedgerAcquire.cpp @@ -124,7 +124,7 @@ void LedgerAcquire::done() setComplete(); mLock.lock(); triggers = mOnComplete; - mOnComplete.empty(); + mOnComplete.clear(); mLock.unlock(); if (mLedger) diff --git a/src/PubKeyCache.cpp b/src/PubKeyCache.cpp index 503fefc3d..4ca514039 100644 --- a/src/PubKeyCache.cpp +++ b/src/PubKeyCache.cpp @@ -69,6 +69,6 @@ CKey::pointer PubKeyCache::store(const NewcoinAddress& id, const CKey::pointer& void PubKeyCache::clear() { boost::mutex::scoped_lock sl(mLock); - mCache.empty(); + mCache.clear(); } // vim:ts=4 diff --git a/src/SerializedObject.cpp b/src/SerializedObject.cpp index fb30248f6..8e6e9df60 100644 --- a/src/SerializedObject.cpp +++ b/src/SerializedObject.cpp @@ -120,8 +120,8 @@ std::auto_ptr STObject::makeDeserializedObject(SerializedTypeID void STObject::set(const std::vector& type) { - mData.empty(); - mType.empty(); + mData.clear(); + mType.clear(); BOOST_FOREACH(const SOElement::ptr& elem, type) { @@ -138,7 +138,7 @@ bool STObject::setType(const std::vector &type) boost::ptr_vector newData; bool valid = true; - mType.empty(); + mType.clear(); BOOST_FOREACH(const SOElement::ptr& elem, type) { bool match = false; @@ -204,7 +204,7 @@ bool STObject::isFieldAllowed(SField::ref field) bool STObject::set(SerializerIterator& sit, int depth) { // return true = terminated with end-of-object - mData.empty(); + mData.clear(); while (!sit.empty()) { int type, field; From 61c9d30732948c84900bf2c65c7558601e623021 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Thu, 11 Oct 2012 05:13:29 -0700 Subject: [PATCH 12/21] Set up to fix the bug Jed reported and also support faulting in nodes under ledgers. --- src/Ledger.cpp | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/Ledger.cpp b/src/Ledger.cpp index 35ffc7dcf..737579df7 100644 --- a/src/Ledger.cpp +++ b/src/Ledger.cpp @@ -24,7 +24,8 @@ SETUP_LOG(); Ledger::Ledger(const NewcoinAddress& masterID, uint64 startAmount) : mTotCoins(startAmount), mLedgerSeq(1), mCloseTime(0), mParentCloseTime(0), mCloseResolution(LEDGER_TIME_ACCURACY), mCloseFlags(0), mClosed(false), mValidHash(false), mAccepted(false), mImmutable(false), - mTransactionMap(new SHAMap(smtTRANSACTION)), mAccountStateMap(new SHAMap(smtFREE)) + mTransactionMap(boost::make_shared(smtTRANSACTION)), + mAccountStateMap(boost::make_shared(smtSTATE)) { // special case: put coins in root account AccountState::pointer startAccount = boost::make_shared(masterID); @@ -42,9 +43,19 @@ Ledger::Ledger(const uint256 &parentHash, const uint256 &transHash, const uint25 : mParentHash(parentHash), mTransHash(transHash), mAccountHash(accountHash), mTotCoins(totCoins), mLedgerSeq(ledgerSeq), mCloseTime(closeTime), mParentCloseTime(parentCloseTime), mCloseResolution(closeResolution), mCloseFlags(closeFlags), - mClosed(false), mValidHash(false), mAccepted(false), mImmutable(isMutable) + mClosed(false), mValidHash(false), mAccepted(false), mImmutable(isMutable), + mTransactionMap(boost::make_shared(smtTRANSACTION)), + mAccountStateMap(boost::make_shared(smtSTATE)) { updateHash(); + if (mTransHash.isNonZero()) + { + // WRITEME + } + if (mAccountHash.isNonZero()) + { + // WRITEME + } } Ledger::Ledger(Ledger& ledger, bool isMutable) : mTotCoins(ledger.mTotCoins), mLedgerSeq(ledger.mLedgerSeq), @@ -62,7 +73,8 @@ Ledger::Ledger(bool /* dummy */, Ledger& prevLedger) : mTotCoins(prevLedger.mTotCoins), mLedgerSeq(prevLedger.mLedgerSeq + 1), mParentCloseTime(prevLedger.mCloseTime), mCloseResolution(prevLedger.mCloseResolution), mCloseFlags(0), mClosed(false), mValidHash(false), mAccepted(false), mImmutable(false), - mTransactionMap(new SHAMap(smtTRANSACTION)), mAccountStateMap(prevLedger.mAccountStateMap->snapShot(true)) + mTransactionMap(boost::make_shared(smtTRANSACTION)), + mAccountStateMap(prevLedger.mAccountStateMap->snapShot(true)) { // Create a new ledger that follows this one prevLedger.updateHash(); mParentHash = prevLedger.getHash(); From 8c790b1d8824c44f5a3288985fc2c744fb428360 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Thu, 11 Oct 2012 05:17:35 -0700 Subject: [PATCH 13/21] Remove dead code. --- src/NetworkOPs.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/NetworkOPs.cpp b/src/NetworkOPs.cpp index 855128bdf..6a01d4268 100644 --- a/src/NetworkOPs.cpp +++ b/src/NetworkOPs.cpp @@ -585,7 +585,6 @@ bool NetworkOPs::checkLastClosedLedger(const std::vector& peerLis if (!mAcquiringLedger->isComplete()) { // add more peers int count = 0; - std::vector peers=theApp->getConnectionPool().getPeerVector(); BOOST_FOREACH(Peer::ref it, peerList) { if (it->getClosedLedgerHash() == closedLedger) From 07cd8ad9bd22c605cda0b6bca7df384a31456962 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Thu, 11 Oct 2012 06:04:06 -0700 Subject: [PATCH 14/21] Some extra debug on the dirty node flush code. It appears good. --- src/Ledger.cpp | 9 +++++---- src/SHAMap.cpp | 2 ++ 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/Ledger.cpp b/src/Ledger.cpp index 737579df7..92f562154 100644 --- a/src/Ledger.cpp +++ b/src/Ledger.cpp @@ -340,10 +340,11 @@ void Ledger::saveAcceptedLedger(Ledger::ref ledger) ledger->mAccountHash.GetHex() % ledger->mTransHash.GetHex())); // write out dirty nodes - while(ledger->mTransactionMap->flushDirty(256, hotTRANSACTION_NODE, ledger->mLedgerSeq)) - { ; } - while(ledger->mAccountStateMap->flushDirty(256, hotACCOUNT_NODE, ledger->mLedgerSeq)) - { ; } + int fc; + while ((fc = ledger->mTransactionMap->flushDirty(256, hotTRANSACTION_NODE, ledger->mLedgerSeq)) > 0) + { cLog(lsINFO) << "Flushed " << fc << " dirty transaction nodes"; } + while ((fc = ledger->mAccountStateMap->flushDirty(256, hotACCOUNT_NODE, ledger->mLedgerSeq)) > 0) + { cLog(lsINFO) << "Flushed " << fc << " dirty state nodes"; } ledger->disarmDirty(); SHAMap& txSet = *ledger->peekTransactionMap(); diff --git a/src/SHAMap.cpp b/src/SHAMap.cpp index efd97e266..3d6f70620 100644 --- a/src/SHAMap.cpp +++ b/src/SHAMap.cpp @@ -725,6 +725,8 @@ int SHAMap::flushDirty(int maxNodes, HashedObjectType t, uint32 seq) boost::unordered_map::iterator it = dirtyNodes.begin(); while (it != dirtyNodes.end()) { + tLog(mType == smtTRANSACTION, lsDEBUG) << "TX node write " << it->first; + tLog(mType == smtSTATE, lsDEBUG) << "STATE node write " << it->first; s.erase(); it->second->addRaw(s, snfPREFIX); theApp->getHashedObjectStore().store(t, seq, s.peekData(), s.getSHA512Half()); From 55e38c40f72a9e7e60c54fa4bf69cb840c602bf9 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Thu, 11 Oct 2012 07:01:03 -0700 Subject: [PATCH 15/21] Cleanups. --- src/SHAMap.cpp | 10 ++++++++++ src/SHAMap.h | 3 +++ 2 files changed, 13 insertions(+) diff --git a/src/SHAMap.cpp b/src/SHAMap.cpp index 3d6f70620..09877fa40 100644 --- a/src/SHAMap.cpp +++ b/src/SHAMap.cpp @@ -690,7 +690,10 @@ SHAMapTreeNode::pointer SHAMap::fetchNodeExternal(const SHAMapNode& id, const ui HashedObject::pointer obj(theApp->getHashedObjectStore().retrieve(hash)); if (!obj) + { + Log(lsTRACE) << "fetchNodeExternal: missing " << hash; throw SHAMapMissingNode(mType, id, hash); + } assert(Serializer::getSHA512Half(obj->getData()) == hash); try @@ -708,6 +711,13 @@ SHAMapTreeNode::pointer SHAMap::fetchNodeExternal(const SHAMapNode& id, const ui } } +void SHAMap::fetchRoot(const uint256& hash) +{ + root = fetchNodeExternal(SHAMapNode(), hash); + root->makeInner(); + mTNByID[*root] = root; +} + void SHAMap::armDirty() { // begin saving dirty nodes ++mSeq; diff --git a/src/SHAMap.h b/src/SHAMap.h index 72a4f23c3..f144b5ca9 100644 --- a/src/SHAMap.h +++ b/src/SHAMap.h @@ -273,6 +273,8 @@ public: bool hasTargetIndex() const { return !mTargetIndex.isZero(); } }; +extern std::ostream& operator<<(std::ostream&, const SHAMapMissingNode&); + class SHAMap { public: @@ -330,6 +332,7 @@ public: ScopedLock Lock() const { return ScopedLock(mLock); } bool hasNode(const SHAMapNode& id); + void fetchRoot(const uint256& hash); // normal hash access functions bool hasItem(const uint256& id); From cf6206f19b2a52e5b69d2f2c2403b6c500c22ab4 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Thu, 11 Oct 2012 07:01:23 -0700 Subject: [PATCH 16/21] Some nicer logging. --- src/SHAMapNodes.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/SHAMapNodes.cpp b/src/SHAMapNodes.cpp index 746176aba..ad1e27749 100644 --- a/src/SHAMapNodes.cpp +++ b/src/SHAMapNodes.cpp @@ -18,6 +18,9 @@ std::string SHAMapNode::getString() const { + if ((mDepth == 0) && (mNodeID.isZero())) + return "NodeID(root)"; + return str(boost::format("NodeID(%s,%s)") % boost::lexical_cast(mDepth) % mNodeID.GetHex()); @@ -507,4 +510,16 @@ bool SHAMapTreeNode::setChildHash(int m, const uint256 &hash) return updateHash(); } +std::ostream& operator<<(std::ostream& out, const SHAMapMissingNode& mn) +{ + if (mn.getMapType() == smtTRANSACTION) + out << "Missing/TXN(" << mn.getNodeID() << ")"; + else if (mn.getMapType() == smtSTATE) + out << "Missing/STA(" << mn.getNodeID() << ")"; + else + out << "Missing/" << mn.getNodeID(); +} + + + // vim:ts=4 From e18f8c47f5ce7a94e37a71e0ddc34c1525c79305 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Thu, 11 Oct 2012 07:01:40 -0700 Subject: [PATCH 17/21] Use the local hashed object store to jump start fetching a ledger. --- src/LedgerAcquire.cpp | 39 +++++++++++++++++++++++++++++++++++++++ src/LedgerAcquire.h | 1 + 2 files changed, 40 insertions(+) diff --git a/src/LedgerAcquire.cpp b/src/LedgerAcquire.cpp index 1eac7dc3f..95cf41415 100644 --- a/src/LedgerAcquire.cpp +++ b/src/LedgerAcquire.cpp @@ -96,6 +96,45 @@ LedgerAcquire::LedgerAcquire(const uint256& hash) : PeerSet(hash, LEDGER_ACQUIRE #endif } +bool LedgerAcquire::tryLocal() +{ // return value: true = no more work to do + HashedObject::pointer node = theApp->getHashedObjectStore().retrieve(mHash); + if (!node) + return false; + + mLedger = boost::make_shared(strCopy(node->getData())); + assert(mLedger->getHash() == mHash); + mHaveBase = true; + + if (!mLedger->getTransHash()) + mHaveTransactions = true; + else + { + try + { + mLedger->peekTransactionMap()->fetchRoot(mLedger->getTransHash()); + } + catch (SHAMapMissingNode&) + { + } + } + + if (!mLedger->getAccountHash()) + mHaveState = true; + else + { + try + { + mLedger->peekAccountStateMap()->fetchRoot(mLedger->getAccountHash()); + } + catch (SHAMapMissingNode&) + { + } + } + + return mHaveTransactions && mHaveState; +} + void LedgerAcquire::onTimer() { if (getTimeouts() > 6) diff --git a/src/LedgerAcquire.h b/src/LedgerAcquire.h index b58961829..7e2da168d 100644 --- a/src/LedgerAcquire.h +++ b/src/LedgerAcquire.h @@ -94,6 +94,7 @@ public: bool takeAsNode(const std::list& IDs, const std::list >& data); bool takeAsRootNode(const std::vector& data); void trigger(Peer::ref, bool timer); + bool tryLocal(); }; class LedgerAcquireMaster From 4a8668557447485bf972609da140eb971ca3d253 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Thu, 11 Oct 2012 07:02:02 -0700 Subject: [PATCH 18/21] A ledger fetched from SQL is always immutable. --- src/Ledger.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Ledger.h b/src/Ledger.h index 41e30d2db..ffb9dbd81 100644 --- a/src/Ledger.h +++ b/src/Ledger.h @@ -93,7 +93,7 @@ public: Ledger(const uint256 &parentHash, const uint256 &transHash, const uint256 &accountHash, uint64 totCoins, uint32 closeTime, uint32 parentCloseTime, int closeFlags, int closeResolution, - uint32 ledgerSeq, bool immutable); // used for database ledgers + uint32 ledgerSeq); // used for database ledgers Ledger(const std::vector& rawLedger); From 37f246396fc4bf4861104c23787c86de5cab3b01 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Thu, 11 Oct 2012 07:02:25 -0700 Subject: [PATCH 19/21] Try to populate the ledger root. --- src/Ledger.cpp | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/src/Ledger.cpp b/src/Ledger.cpp index 92f562154..53491b991 100644 --- a/src/Ledger.cpp +++ b/src/Ledger.cpp @@ -39,23 +39,21 @@ Ledger::Ledger(const NewcoinAddress& masterID, uint64 startAmount) : mTotCoins(s } Ledger::Ledger(const uint256 &parentHash, const uint256 &transHash, const uint256 &accountHash, - uint64 totCoins, uint32 closeTime, uint32 parentCloseTime, int closeFlags, int closeResolution, uint32 ledgerSeq,bool isMutable) + uint64 totCoins, uint32 closeTime, uint32 parentCloseTime, int closeFlags, int closeResolution, uint32 ledgerSeq) : mParentHash(parentHash), mTransHash(transHash), mAccountHash(accountHash), mTotCoins(totCoins), mLedgerSeq(ledgerSeq), mCloseTime(closeTime), mParentCloseTime(parentCloseTime), mCloseResolution(closeResolution), mCloseFlags(closeFlags), - mClosed(false), mValidHash(false), mAccepted(false), mImmutable(isMutable), - mTransactionMap(boost::make_shared(smtTRANSACTION)), - mAccountStateMap(boost::make_shared(smtSTATE)) + mClosed(false), mValidHash(false), mAccepted(false), mImmutable(true), + mTransactionMap(boost::make_shared(smtTRANSACTION, transHash)), + mAccountStateMap(boost::make_shared(smtSTATE, accountHash)) { updateHash(); if (mTransHash.isNonZero()) - { - // WRITEME - } + mTransactionMap->fetchRoot(mTransHash); if (mAccountHash.isNonZero()) - { - // WRITEME - } + mAccountStateMap->fetchRoot(mAccountHash); + mTransactionMap->setImmutable(); + mAccountStateMap->setImmutable(); } Ledger::Ledger(Ledger& ledger, bool isMutable) : mTotCoins(ledger.mTotCoins), mLedgerSeq(ledger.mLedgerSeq), @@ -438,7 +436,7 @@ Ledger::pointer Ledger::getSQL(const std::string& sql) } Ledger::pointer ret = Ledger::pointer(new Ledger(prevHash, transHash, accountHash, totCoins, - closingTime, prevClosingTime, closeFlags, closeResolution, ledgerSeq, true)); + closingTime, prevClosingTime, closeFlags, closeResolution, ledgerSeq)); if (ret->getHash() != ledgerHash) { if (sLog(lsERROR)) From ac8e2292cf7bed6e7b48193932aa751248bcafcf Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Thu, 11 Oct 2012 07:03:14 -0700 Subject: [PATCH 20/21] Add a comment. --- src/Ledger.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Ledger.cpp b/src/Ledger.cpp index 53491b991..5be6eb02b 100644 --- a/src/Ledger.cpp +++ b/src/Ledger.cpp @@ -46,7 +46,7 @@ Ledger::Ledger(const uint256 &parentHash, const uint256 &transHash, const uint25 mClosed(false), mValidHash(false), mAccepted(false), mImmutable(true), mTransactionMap(boost::make_shared(smtTRANSACTION, transHash)), mAccountStateMap(boost::make_shared(smtSTATE, accountHash)) -{ +{ // This will throw if the root nodes are not available locally updateHash(); if (mTransHash.isNonZero()) mTransactionMap->fetchRoot(mTransHash); From 2a13b9b7db8b45950373dd6bf5bf8b91dfd8edd8 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Thu, 11 Oct 2012 07:03:21 -0700 Subject: [PATCH 21/21] Fix the '--load' logic. --- src/Application.cpp | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/src/Application.cpp b/src/Application.cpp index fa8861fa1..11b19895b 100644 --- a/src/Application.cpp +++ b/src/Application.cpp @@ -208,17 +208,25 @@ void Application::startNewLedger() void Application::loadOldLedger() { - Ledger::pointer lastLedger = Ledger::getSQL("SELECT * from Ledgers order by LedgerSeq desc limit 1;"); - - if (!lastLedger) + try { - std::cout << "No Ledger found?" << std::endl; + Ledger::pointer lastLedger = Ledger::getSQL("SELECT * from Ledgers order by LedgerSeq desc limit 1;"); + + if (!lastLedger) + { + std::cout << "No Ledger found?" << std::endl; + exit(-1); + } + lastLedger->setClosed(); + + Ledger::pointer openLedger = boost::make_shared(false, boost::ref(*lastLedger)); + mMasterLedger.switchLedgers(lastLedger, openLedger); + mNetOps.setLastCloseTime(lastLedger->getCloseTimeNC()); + } + catch (SHAMapMissingNode& mn) + { + Log(lsFATAL) << "Cannot load ledger. " << mn; exit(-1); } - lastLedger->setClosed(); - - Ledger::pointer openLedger = boost::make_shared(false, boost::ref(*lastLedger)); - mMasterLedger.switchLedgers(lastLedger, openLedger); - mNetOps.setLastCloseTime(lastLedger->getCloseTimeNC()); } // vim:ts=4