From d554950efe63f2239949d95dba874027aff614ec Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 13 Aug 2012 14:35:47 -0700 Subject: [PATCH 01/20] One more drop of extra debug. --- src/LedgerConsensus.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index ede0804cc4..1cb3d288cf 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -876,7 +876,8 @@ void LedgerConsensus::accept(SHAMap::pointer set) if (mHaveCorrectLCL) { Log(lsINFO) << "CNF tx " << mOurPosition->getCurrentHash().GetHex() << ", close " << closeTime; - Log(lsINFO) << "CNF oldLCL " << mPrevLedgerHash.GetHex(); + Log(lsINFO) << "CNF mode " << theApp->getOPs().getOperatingMode() + << ", oldLCL " << mPrevLedgerHash.GetHex(); } Ledger::pointer newLCL = boost::make_shared(false, boost::ref(*mPreviousLedger)); From 99a3d833300c90c3a9e7e69c65bd979004179962 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 13 Aug 2012 14:56:08 -0700 Subject: [PATCH 02/20] Indent fix. --- src/LedgerTiming.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/LedgerTiming.cpp b/src/LedgerTiming.cpp index ecff1f441a..ae0d65de19 100644 --- a/src/LedgerTiming.cpp +++ b/src/LedgerTiming.cpp @@ -17,7 +17,7 @@ int ContinuousLedgerTiming::shouldClose( int previousProposers, // proposers in the last closing int proposersClosed, // proposers who have currently closed this ledgers int previousMSeconds, // seconds the previous ledger took to reach consensus - int currentMSeconds) // seconds since the previous ledger closed + int currentMSeconds) // seconds since the previous ledger closed { if ((previousMSeconds < -1000) || (previousMSeconds > 600000) || (currentMSeconds < -1000) || (currentMSeconds > 600000)) From 0f51774f58612a4971cb9b4929fb234da4d87d49 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 13 Aug 2012 15:10:38 -0700 Subject: [PATCH 03/20] Some paranoid extra checks. --- src/LedgerConsensus.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index 1cb3d288cf..7d9f1c3d6c 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -544,6 +544,8 @@ void LedgerConsensus::updateOurPositions() ++thresh; } thresh = thresh * neededWeight / 100; + if (thresh == 0) + thresh = 1; for (std::map::iterator it = closeTimes.begin(), end = closeTimes.end(); it != end; ++it) { @@ -553,6 +555,7 @@ void LedgerConsensus::updateOurPositions() Log(lsINFO) << "Close time consensus reached: " << closeTime; mHaveCloseTimeConsensus = true; closeTime = it->first; + thresh = it->second; } } } From 9e41cac0dad99c7d8dcaffbd51c0977027a58c39 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Mon, 13 Aug 2012 17:05:35 -0700 Subject: [PATCH 04/20] Add RPC ripple command and improve wallet_propose. --- src/RPCServer.cpp | 286 +++++++++++++++++++++++++++++++++++++--- src/RPCServer.h | 3 + src/SerializedTypes.cpp | 6 + src/SerializedTypes.h | 31 +++-- src/main.cpp | 3 +- 5 files changed, 299 insertions(+), 30 deletions(-) diff --git a/src/RPCServer.cpp b/src/RPCServer.cpp index 0ac81e6b54..46ea9eda7d 100644 --- a/src/RPCServer.cpp +++ b/src/RPCServer.cpp @@ -44,6 +44,7 @@ Json::Value RPCServer::RPCError(int iError) { rpcBAD_SEED, "badSeed", "Disallowed seed." }, { rpcDST_ACT_MALFORMED, "dstActMalformed", "Destination account is malformed." }, { rpcDST_AMT_MALFORMED, "dstAmtMalformed", "Destination amount/currency is malformed." }, + { rpcDST_ACT_MISSING, "dstActMissing", "Destination account does not exists." }, { rpcFAIL_GEN_DECRPYT, "failGenDecrypt", "Failed to decrypt generator." }, { rpcGETS_ACT_MALFORMED, "getsActMalformed", "Gets account malformed." }, { rpcGETS_AMT_MALFORMED, "getsAmtMalformed", "Gets ammount malformed." }, @@ -70,8 +71,8 @@ Json::Value RPCServer::RPCError(int iError) { rpcPORT_MALFORMED, "portMalformed", "Port is malformed." }, { rpcPUBLIC_MALFORMED, "publicMalformed", "Public key is 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_MISSING, "srcMissing", "Source account does not exist." }, { rpcSRC_UNCLAIMED, "srcUnclaimed", "Source account is not claimed." }, { rpcSUCCESS, "success", "Success." }, { rpcTXN_NOT_FOUND, "txnNotFound", "Transaction not found." }, @@ -279,7 +280,7 @@ Json::Value RPCServer::authorize(const uint256& uLedger, asSrc = mNetOps->getAccountState(uLedger, naSrcAccountID); if (!asSrc) { - return RPCError(rpcSRC_MISSING); + return RPCError(rpcSRC_ACT_MISSING); } NewcoinAddress naMasterGenerator; @@ -546,7 +547,7 @@ Json::Value RPCServer::doAccountInfo(const Json::Value ¶ms) { std::string strIdent = params[0u].asString(); bool bIndex; - int iIndex = 2 == params.size()? lexical_cast_s(params[1u].asString()) : 0; + int iIndex = 2 == params.size() ? lexical_cast_s(params[1u].asString()) : 0; NewcoinAddress naAccount; Json::Value ret; @@ -1385,6 +1386,239 @@ Json::Value RPCServer::doRippleLineSet(const Json::Value& params) } } + +// ripple +// [noredeem] [noissue] +// + +// full|partial +// +// path: +// path + +// +// path_element: +// account [] [] [noredeem] [noissue] +// offer [] +Json::Value RPCServer::doRipple(const Json::Value ¶ms) +{ + NewcoinAddress naSeed; + STAmount saSrcAmountMax; + uint160 uSrcCurrencyID; + NewcoinAddress naSrcAccountID; + bool bSrcRedeem = true; + bool bSrcIssue = true; + bool bPartial; + bool bFull; + NewcoinAddress naDstAccountID; + STAmount saDstAmount; + uint160 uDstCurrencyID; + NewcoinAddress naDstIssuerID; + + std::vector vpnPath; + STPathSet spsPaths; + + if (!naSeed.setSeedGeneric(params[0u].asString())) // + { + return RPCError(rpcBAD_SEED); + } + else if (!naSrcAccountID.setAccountID(params[1u].asString())) // + { + return RPCError(rpcSRC_ACT_MALFORMED); + } + // + else if (!saSrcAmountMax.setFullValue(params[2u].asString(), params[3u].asString(), params[4u].asString())) + { + return RPCError(rpcSRC_AMT_MALFORMED); + } + + int iArg = 5; + + if (params[iArg].asString() == "noredeem") // [noredeem] + { + ++iArg; + bSrcRedeem = false; + } + + if (params[iArg].asString() == "noissue") // [noissue] + { + ++iArg; + bSrcIssue = false; + } + + // XXX bSrcRedeem & bSrcIssue not used. + STPath spPath; + + while (params.size() != iArg && params[iArg].asString() == "path") // path + { + Log(lsINFO) << "Path>"; + ++iArg; + + while (params.size() != iArg + && (params[iArg].asString() == "offer" || params[iArg].asString() == "account")) + { + if (params.size() >= iArg + 3 && params[iArg].asString() == "offer") // offer + { + Log(lsINFO) << "Offer>"; + uint160 uCurrencyID; + NewcoinAddress naIssuerID; + + ++iArg; + + if (!STAmount::currencyFromString(uCurrencyID, params[iArg++].asString())) // + { + return RPCError(rpcINVALID_PARAMS); + } + else if (naIssuerID.setAccountID(params[iArg].asString())) // [] + { + ++iArg; + } + + spPath.addElement(STPathElement( + uint160(0), + uCurrencyID, + naIssuerID.isValid() ? naIssuerID.getAccountID() : uint160(0))); + } + else if (params.size() >= iArg + 2 && params[iArg].asString() == "account") // account + { + Log(lsINFO) << "Account>"; + NewcoinAddress naAccountID; + uint160 uCurrencyID; + NewcoinAddress naIssuerID; + bool bRedeem = true; + bool bIssue = true; + + ++iArg; + + if (!naAccountID.setAccountID(params[iArg++].asString())) // + { + return RPCError(rpcINVALID_PARAMS); + } + + if (params.size() != iArg && STAmount::currencyFromString(uCurrencyID, params[iArg].asString())) // [] + { + ++iArg; + } + + if (params.size() != iArg && naIssuerID.setAccountID(params[iArg].asString())) // [] + { + ++iArg; + } + + if (params.size() != iArg && params[iArg].asString() == "noredeem") // [noredeem] + { + ++iArg; + bRedeem = false; + } + + if (params.size() != iArg && params[iArg].asString() == "noissue") // [noissue] + { + ++iArg; + bIssue = false; + } + + spPath.addElement(STPathElement( + naAccountID.getAccountID(), + uCurrencyID, + naIssuerID.isValid() ? naIssuerID.getAccountID() : uint160(0), + bRedeem, + bIssue)); + } + else + { + return RPCError(rpcINVALID_PARAMS); + } + } + + if (spPath.isEmpty()) + { + return RPCError(rpcINVALID_PARAMS); + } + else + { + spsPaths.addPath(spPath); + spPath.clear(); + } + } + + // full|partial + bPartial = params.size() != iArg ? params[iArg].asString() == "partial" : false; + bFull = params.size() != iArg ? params[iArg].asString() == "full" : false; + + if (!bPartial && !bFull) + { + return RPCError(rpcINVALID_PARAMS); + } + else + { + ++iArg; + } + + if (params.size() != iArg && !naDstAccountID.setAccountID(params[iArg++].asString())) // + { + return RPCError(rpcDST_ACT_MALFORMED); + } + // + else if (params.size() != iArg + 3 || !saDstAmount.setFullValue(params[iArg].asString(), params[iArg+1].asString(), params[iArg+2].asString())) + { + Log(lsINFO) << "params.size(): " << params.size(); + Log(lsINFO) << " iArg: " << iArg; + Log(lsINFO) << " Amount: " << params[iArg].asString(); + Log(lsINFO) << "Currency: " << params[iArg+1].asString(); + Log(lsINFO) << " Issuer: " << params[iArg+2].asString(); + + return RPCError(rpcDST_AMT_MALFORMED); + } + + uint256 uLedger = mNetOps->getCurrentLedger(); + AccountState::pointer asDst = mNetOps->getAccountState(uLedger, naDstAccountID); + STAmount saFee = theConfig.FEE_DEFAULT; + + NewcoinAddress naVerifyGenerator; + NewcoinAddress naAccountPublic; + NewcoinAddress naAccountPrivate; + AccountState::pointer asSrc; + STAmount saSrcBalance; + Json::Value obj = authorize(uLedger, naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, + saSrcBalance, saFee, asSrc, naVerifyGenerator); + + if (!obj.empty()) + return obj; + + // YYY Could do some checking: source has funds or credit, dst exists and has sufficent credit limit. + // YYY Currency from same source or loops not allowed. + // YYY Limit paths length and count. + if (!asDst) + { + return RPCError(rpcDST_ACT_MISSING); + } + + Transaction::pointer trans = Transaction::sharedPayment( + naAccountPublic, naAccountPrivate, + naSrcAccountID, + asSrc->getSeq(), + saFee, + 0, // YYY No source tag + naDstAccountID, + saDstAmount, + saSrcAmountMax, + spsPaths); + + trans = mNetOps->submitTransaction(trans); + + obj["transaction"] = trans->getSTransaction()->getJson(0); + obj["status"] = trans->getStatus(); + obj["seed"] = naSeed.humanSeed(); + obj["fee"] = saFee.getText(); + obj["srcAccountID"] = naSrcAccountID.humanAccountID(); + obj["dstAccountID"] = naDstAccountID.humanAccountID(); + obj["srcAmountMax"] = saSrcAmountMax.getText(); + obj["srcISO"] = saSrcAmountMax.getHumanCurrency(); + obj["dstAmount"] = saDstAmount.getText(); + obj["dstISO"] = saDstAmount.getHumanCurrency(); + obj["paths"] = spsPaths.getText(); + + return obj; +} + // ripple_lines_get || [] Json::Value RPCServer::doRippleLinesGet(const Json::Value ¶ms) { @@ -1393,7 +1627,7 @@ Json::Value RPCServer::doRippleLinesGet(const Json::Value ¶ms) std::string strIdent = params[0u].asString(); bool bIndex; - int iIndex = 2 == params.size()? lexical_cast_s(params[1u].asString()) : 0; + int iIndex = 2 == params.size() ? lexical_cast_s(params[1u].asString()) : 0; NewcoinAddress naAccount; @@ -1501,11 +1735,10 @@ Json::Value RPCServer::doSend(const Json::Value& params) NewcoinAddress naSeed; NewcoinAddress naSrcAccountID; NewcoinAddress naDstAccountID; - STAmount saSrcAmount; + STAmount saSrcAmountMax; STAmount saDstAmount; std::string sSrcCurrency; std::string sDstCurrency; - uint256 uLedger = mNetOps->getCurrentLedger(); if (params.size() >= 5) sDstCurrency = params[4u].asString(); @@ -1529,12 +1762,13 @@ Json::Value RPCServer::doSend(const Json::Value& params) { return RPCError(rpcDST_AMT_MALFORMED); } - else if (params.size() >= 6 && !saSrcAmount.setFullValue(params[5u].asString(), sSrcCurrency)) + else if (params.size() >= 6 && !saSrcAmountMax.setFullValue(params[5u].asString(), sSrcCurrency)) { return RPCError(rpcSRC_AMT_MALFORMED); } else { + uint256 uLedger = mNetOps->getCurrentLedger(); AccountState::pointer asDst = mNetOps->getAccountState(uLedger, naDstAccountID); bool bCreate = !asDst; STAmount saFee = bCreate ? theConfig.FEE_ACCOUNT_CREATE : theConfig.FEE_DEFAULT; @@ -1551,10 +1785,10 @@ Json::Value RPCServer::doSend(const Json::Value& params) return obj; if (params.size() < 6) - saSrcAmount = saDstAmount; + saSrcAmountMax = saDstAmount; // Do a few simple checks. - if (!saSrcAmount.isNative()) + if (!saSrcAmountMax.isNative()) { Log(lsINFO) << "doSend: Ripple"; @@ -1567,11 +1801,11 @@ Json::Value RPCServer::doSend(const Json::Value& params) return RPCError(rpcINSUF_FUNDS); } - else if (saDstAmount.isNative() && saSrcAmount < saDstAmount) + else if (saDstAmount.isNative() && saSrcAmountMax < saDstAmount) { // Not enough native currency. - Log(lsINFO) << "doSend: Insufficient funds: src=" << saSrcAmount.getText() << " dst=" << saDstAmount.getText(); + Log(lsINFO) << "doSend: Insufficient funds: src=" << saSrcAmountMax.getText() << " dst=" << saDstAmount.getText(); return RPCError(rpcINSUF_FUNDS); } @@ -1582,7 +1816,7 @@ Json::Value RPCServer::doSend(const Json::Value& params) if (asDst) { // Destination exists, ordinary send. - STPathSet spPaths; + STPathSet spsPaths; trans = Transaction::sharedPayment( naAccountPublic, naAccountPrivate, @@ -1592,8 +1826,8 @@ Json::Value RPCServer::doSend(const Json::Value& params) 0, // YYY No source tag naDstAccountID, saDstAmount, - saSrcAmount, - spPaths); + saSrcAmountMax, + spsPaths); } else { @@ -1618,8 +1852,8 @@ Json::Value RPCServer::doSend(const Json::Value& params) obj["create"] = bCreate; obj["srcAccountID"] = naSrcAccountID.humanAccountID(); obj["dstAccountID"] = naDstAccountID.humanAccountID(); - obj["srcAmount"] = saSrcAmount.getText(); - obj["srcISO"] = saSrcAmount.getHumanCurrency(); + obj["srcAmountMax"] = saSrcAmountMax.getText(); + obj["srcISO"] = saSrcAmountMax.getHumanCurrency(); obj["dstAmount"] = saDstAmount.getText(); obj["dstISO"] = saDstAmount.getHumanCurrency(); @@ -2156,13 +2390,21 @@ Json::Value RPCServer::doWalletCreate(const Json::Value& params) return obj; } -// wallet_propose +// wallet_propose [] +// is only for testing. Master seeds should only be generated randomly. Json::Value RPCServer::doWalletPropose(const Json::Value& params) { NewcoinAddress naSeed; NewcoinAddress naAccount; - naSeed.setSeedRandom(); + if (params.empty()) + { + naSeed.setSeedRandom(); + } + else + { + naSeed = NewcoinAddress::createSeedGeneric(params[0u].asString()); + } NewcoinAddress naGenerator = NewcoinAddress::createGeneratorPublic(naSeed); naAccount.setAccountPublic(naGenerator, 0); @@ -2332,7 +2574,8 @@ Json::Value RPCServer::doCommand(const std::string& command, Json::Value& params { "password_fund", &RPCServer::doPasswordFund, 2, 3, false, optCurrent }, { "password_set", &RPCServer::doPasswordSet, 2, 3, false, optNetwork }, { "peers", &RPCServer::doPeers, 0, 0, true }, - { "ripple_lines_get", &RPCServer::doRippleLinesGet, 1, 2, false, optCurrent|optClosed }, + { "ripple", &RPCServer::doRipple, 10, -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 }, { "server_info", &RPCServer::doServerInfo, 0, 0, true }, @@ -2354,7 +2597,7 @@ Json::Value RPCServer::doCommand(const std::string& command, Json::Value& params { "wallet_add", &RPCServer::doWalletAdd, 3, 5, false, optCurrent }, { "wallet_claim", &RPCServer::doWalletClaim, 2, 4, false, optNetwork }, { "wallet_create", &RPCServer::doWalletCreate, 3, 4, false, optCurrent }, - { "wallet_propose", &RPCServer::doWalletPropose, 0, 0, false, }, + { "wallet_propose", &RPCServer::doWalletPropose, 0, 1, false, }, { "wallet_seed", &RPCServer::doWalletSeed, 0, 1, false, }, { "login", &RPCServer::doLogin, 2, 2, true }, @@ -2373,7 +2616,8 @@ Json::Value RPCServer::doCommand(const std::string& command, Json::Value& params { return RPCError(rpcNO_PERMISSION); } - else if (params.size() < commandsA[i].iMinParams || params.size() > commandsA[i].iMaxParams) + else if (params.size() < commandsA[i].iMinParams + || (commandsA[i].iMaxParams >= 0 && params.size() > commandsA[i].iMaxParams)) { return RPCError(rpcINVALID_PARAMS); } diff --git a/src/RPCServer.h b/src/RPCServer.h index 539dcf2e7d..eb847b2e07 100644 --- a/src/RPCServer.h +++ b/src/RPCServer.h @@ -50,6 +50,7 @@ public: rpcACT_MALFORMED, rpcBAD_SEED, rpcDST_ACT_MALFORMED, + rpcDST_ACT_MISSING, rpcDST_AMT_MALFORMED, rpcGETS_ACT_MALFORMED, rpcGETS_AMT_MALFORMED, @@ -63,6 +64,7 @@ public: rpcPORT_MALFORMED, rpcPUBLIC_MALFORMED, rpcSRC_ACT_MALFORMED, + rpcSRC_ACT_MISSING, rpcSRC_AMT_MALFORMED, // Internal error (should never happen) @@ -146,6 +148,7 @@ private: Json::Value doPasswordFund(const Json::Value& params); Json::Value doPasswordSet(const Json::Value& params); Json::Value doPeers(const Json::Value& params); + Json::Value doRipple(const Json::Value ¶ms); Json::Value doRippleLinesGet(const Json::Value ¶ms); Json::Value doRippleLineSet(const Json::Value& params); Json::Value doSend(const Json::Value& params); diff --git a/src/SerializedTypes.cpp b/src/SerializedTypes.cpp index df263827e3..cd759e1ee2 100644 --- a/src/SerializedTypes.cpp +++ b/src/SerializedTypes.cpp @@ -346,6 +346,12 @@ STPathSet* STPathSet::construct(SerializerIterator& s, const char *name) } while(1); } +bool STPathSet::isEquivalent(const SerializedType& t) const +{ + const STPathSet* v = dynamic_cast(&t); + return v && (value == v->value); +} + int STPathSet::getLength() const { int ret = 0; diff --git a/src/SerializedTypes.h b/src/SerializedTypes.h index fc5e80d0dd..41bcafc33d 100644 --- a/src/SerializedTypes.h +++ b/src/SerializedTypes.h @@ -290,7 +290,7 @@ public: bool isNative() const { return mIsNative; } bool isZero() const { return mValue == 0; } - bool isNonZero() const { return mValue != 0; } + bool isNonZero() const { return mValue != 0; } bool isNegative() const { return mIsNegative && !isZero(); } bool isPositive() const { return !mIsNegative && !isZero(); } bool isGEZero() const { return !mIsNegative; } @@ -528,23 +528,31 @@ public: typeCurrency = 0x10, // Currency follows. typeIssuer = 0x20, // Issuer follows. typeBoundary = 0xFF, // Boundary between alternate paths. - typeValidBits = 0x3E, // Bits that may be non-zero. + typeValidBits = ( + typeAccount + | typeRedeem + | typeIssue + | typeCurrency + | typeIssuer + ), // Bits that may be non-zero. }; protected: int mType; uint160 mAccountID; - uint160 mCurrency; + uint160 mCurrencyID; uint160 mIssuerID; public: - STPathElement(const uint160& uAccountID, const uint160& uCurrency, const uint160& uIssuerID) - : mAccountID(uAccountID), mCurrency(uCurrency), mIssuerID(uIssuerID) + STPathElement(const uint160& uAccountID, const uint160& uCurrencyID, const uint160& uIssuerID, bool bRedeem=false, bool bIssue=false) + : mAccountID(uAccountID), mCurrencyID(uCurrencyID), mIssuerID(uIssuerID) { mType = (uAccountID.isZero() ? 0 : STPathElement::typeAccount) - | (uCurrency.isZero() ? 0 : STPathElement::typeCurrency) - | (uIssuerID.isZero() ? 0 : STPathElement::typeIssuer); + | (uCurrencyID.isZero() ? 0 : STPathElement::typeCurrency) + | (uIssuerID.isZero() ? 0 : STPathElement::typeIssuer) + | (bRedeem ? STPathElement::typeRedeem : 0) + | (bIssue ? STPathElement::typeIssue : 0); } int getNodeType() const { return mType; } @@ -553,8 +561,11 @@ public: // Nodes are either an account ID or a offer prefix. Offer prefixs denote a class of offers. const uint160& getAccountID() const { return mAccountID; } - const uint160& getCurrency() const { return mCurrency; } + const uint160& getCurrency() const { return mCurrencyID; } const uint160& getIssuerID() const { return mIssuerID; } + + bool operator==(const STPathElement& t) const + { return mType == t.mType && mAccountID == t.mAccountID && mCurrencyID == t.mCurrencyID && mIssuerID == mIssuerID; } }; class STPath @@ -580,6 +591,8 @@ public: std::vector::iterator end() { return mPath.end(); } std::vector::const_iterator begin() const { return mPath.begin(); } std::vector::const_iterator end() const { return mPath.end(); } + + bool operator==(const STPath& t) const { return mPath == t.mPath; } }; inline std::vector::iterator range_begin(STPath & x) @@ -647,6 +660,8 @@ public: void clear() { value.clear(); } void addPath(const STPath& e) { value.push_back(e); } + virtual bool isEquivalent(const SerializedType& t) const; + std::vector::iterator begin() { return value.begin(); } std::vector::iterator end() { return value.end(); } std::vector::const_iterator begin() const { return value.begin(); } diff --git a/src/main.cpp b/src/main.cpp index 49d23edf31..155408170a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -58,6 +58,7 @@ void printHelp(const po::options_description& desc) cout << " password_fund []" << endl; cout << " password_set []" << endl; cout << " peers" << endl; + cout << " ripple ..." << endl; cout << " ripple_lines_get || []" << endl; cout << " ripple_line_set [] []" << endl; cout << " send [] [] []" << endl; @@ -75,7 +76,7 @@ void printHelp(const po::options_description& desc) cout << " wallet_accounts " << endl; cout << " wallet_claim [] []" << endl; cout << " wallet_seed [||]" << endl; - cout << " wallet_propose" << endl; + cout << " wallet_propose []" << endl; } int main(int argc, char* argv[]) From 88e938ec50bb0d05a45f01b8375c74587b89c4bd Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 13 Aug 2012 17:10:51 -0700 Subject: [PATCH 05/20] Change TXS acquire timeout. --- src/LedgerAcquire.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/LedgerAcquire.cpp b/src/LedgerAcquire.cpp index 2407616bd6..6e13a883c8 100644 --- a/src/LedgerAcquire.cpp +++ b/src/LedgerAcquire.cpp @@ -11,7 +11,7 @@ #include "HashPrefixes.h" // #define LA_DEBUG -#define LEDGER_ACQUIRE_TIMEOUT 2 +#define LEDGER_ACQUIRE_TIMEOUT 1 #define TRUST_NETWORK PeerSet::PeerSet(const uint256& hash, int interval) : mHash(hash), mTimerInterval(interval), mTimeouts(0), From a7f192c989b0062ac07e659c006e593d8e74081c Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 13 Aug 2012 17:11:00 -0700 Subject: [PATCH 06/20] Cleanups. --- src/LedgerConsensus.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index 7d9f1c3d6c..b47a19ee67 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -26,7 +26,10 @@ TransactionAcquire::TransactionAcquire(const uint256& hash) : PeerSet(hash, 1), void TransactionAcquire::done() { if (mFailed) + { + Log(lsWARNING) << "Failed to acqiure TXs " << mHash.GetHex(); theApp->getOPs().mapComplete(mHash, SHAMap::pointer()); + } else theApp->getOPs().mapComplete(mHash, mMap); } @@ -48,7 +51,7 @@ void TransactionAcquire::trigger(Peer::pointer peer, bool timer) *(tmGL.add_nodeids()) = SHAMapNode().getRawString(); sendRequest(tmGL, peer); } - if (mHaveRoot) + else { std::vector nodeIDs; std::vector nodeHashes; ConsensusTransSetSF sf; @@ -67,10 +70,7 @@ void TransactionAcquire::trigger(Peer::pointer peer, bool timer) tmGL.set_itype(newcoin::liTS_CANDIDATE); for (std::vector::iterator it = nodeIDs.begin(); it != nodeIDs.end(); ++it) *(tmGL.add_nodeids()) = it->getRawString(); - if (peer) - sendRequest(tmGL, peer); - else - sendRequest(tmGL); + sendRequest(tmGL, peer); return; } } From 4aea8c8dfb7efa8eed6ecfac7ed202e330d416df Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 13 Aug 2012 17:11:15 -0700 Subject: [PATCH 07/20] Use fat root semantics when acquire transaction sets. This might save a pass. --- src/Peer.cpp | 8 +++++--- src/SHAMap.h | 2 +- src/SHAMapSync.cpp | 11 ++++++----- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/Peer.cpp b/src/Peer.cpp index 991d18456b..28b79d5024 100644 --- a/src/Peer.cpp +++ b/src/Peer.cpp @@ -928,7 +928,7 @@ void Peer::recvGetLedger(newcoin::TMGetLedger& packet) { SHAMap::pointer map; newcoin::TMLedgerData reply; - bool fatLeaves = true; + bool fatLeaves = true, fatRoot = false; if (packet.itype() == newcoin::liTS_CANDIDATE) { // Request is for a transaction candidate set @@ -952,6 +952,7 @@ void Peer::recvGetLedger(newcoin::TMGetLedger& packet) reply.set_ledgerhash(txHash.begin(), txHash.size()); reply.set_type(newcoin::liTS_CANDIDATE); fatLeaves = false; // We'll already have most transactions + fatRoot = true; // Save a pass } else { // Figure out what ledger they want @@ -1057,7 +1058,7 @@ void Peer::recvGetLedger(newcoin::TMGetLedger& packet) } std::vector nodeIDs; std::list< std::vector > rawNodes; - if(map->getNodeFat(mn, nodeIDs, rawNodes, fatLeaves)) + if(map->getNodeFat(mn, nodeIDs, rawNodes, fatRoot, fatLeaves)) { std::vector::iterator nodeIDIterator; std::list< std::vector >::iterator rawNodeIterator; @@ -1074,7 +1075,8 @@ void Peer::recvGetLedger(newcoin::TMGetLedger& packet) } } } - if (packet.has_requestcookie()) reply.set_requestcookie(packet.requestcookie()); + if (packet.has_requestcookie()) + reply.set_requestcookie(packet.requestcookie()); PackedMessage::pointer oPacket = boost::make_shared(reply, newcoin::mtLEDGER_DATA); sendPacket(oPacket); } diff --git a/src/SHAMap.h b/src/SHAMap.h index 4bfd7999db..2f9e73d529 100644 --- a/src/SHAMap.h +++ b/src/SHAMap.h @@ -327,7 +327,7 @@ public: void getMissingNodes(std::vector& nodeIDs, std::vector& hashes, int max, SHAMapSyncFilter* filter); bool getNodeFat(const SHAMapNode& node, std::vector& nodeIDs, - std::list >& rawNode, bool fatLeaves); + std::list >& rawNode, bool fatRoot, bool fatLeaves); bool getRootNode(Serializer& s, SHANodeFormat format); bool addRootNode(const uint256& hash, const std::vector& rootNode, SHANodeFormat format); bool addRootNode(const std::vector& rootNode, SHANodeFormat format); diff --git a/src/SHAMapSync.cpp b/src/SHAMapSync.cpp index 25c2d019a0..ed76558906 100644 --- a/src/SHAMapSync.cpp +++ b/src/SHAMapSync.cpp @@ -86,7 +86,7 @@ void SHAMap::getMissingNodes(std::vector& nodeIDs, std::vector& nodeIDs, - std::list >& rawNodes, bool fatLeaves) + std::list >& rawNodes, bool fatRoot, bool fatLeaves) { // Gets a node and some of its children boost::recursive_mutex::scoped_lock sl(mLock); @@ -102,7 +102,7 @@ bool SHAMap::getNodeFat(const SHAMapNode& wanted, std::vector& nodeI node->addRaw(s, snfWIRE); rawNodes.push_back(s.peekData()); - if (node->isRoot() || node->isLeaf()) // don't get a fat root, can't get a fat leaf + if ((!fatRoot && node->isRoot()) || node->isLeaf()) // don't get a fat root, can't get a fat leaf return true; for (int i = 0; i < 16; ++i) @@ -141,7 +141,8 @@ bool SHAMap::addRootNode(const std::vector& rootNode, SHANodeForm } SHAMapTreeNode::pointer node = boost::make_shared(SHAMapNode(), rootNode, 0, format); - if (!node) return false; + if (!node) + return false; #ifdef DEBUG node->dump(); @@ -444,7 +445,7 @@ BOOST_AUTO_TEST_CASE( SHAMapSync_test ) destination.setSynching(); - if (!source.getNodeFat(SHAMapNode(), nodeIDs, gotNodes, (rand() % 2) == 0)) + if (!source.getNodeFat(SHAMapNode(), nodeIDs, gotNodes, (rand() % 2) == 0, (rand() % 2) == 0)) { Log(lsFATAL) << "GetNodeFat(root) fails"; BOOST_FAIL("GetNodeFat"); @@ -481,7 +482,7 @@ BOOST_AUTO_TEST_CASE( SHAMapSync_test ) // get as many nodes as possible based on this information for (nodeIDIterator = nodeIDs.begin(); nodeIDIterator != nodeIDs.end(); ++nodeIDIterator) { - if (!source.getNodeFat(*nodeIDIterator, gotNodeIDs, gotNodes, (rand() % 2) == 0)) + if (!source.getNodeFat(*nodeIDIterator, gotNodeIDs, gotNodes, (rand() % 2) == 0, (rand() % 2) == 0)) { Log(lsFATAL) << "GetNodeFat fails"; BOOST_FAIL("GetNodeFat"); From e3b6ec5080f5d73bbeba136f136f9376a145ce33 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 13 Aug 2012 17:18:58 -0700 Subject: [PATCH 08/20] Don't call newLCL more than once. --- src/LedgerConsensus.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index b47a19ee67..a2888f190a 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -441,9 +441,7 @@ void LedgerConsensus::stateEstablish() void LedgerConsensus::stateFinished() { // we are processing the finished ledger // logic of calculating next ledger advances us out of this state - - // CHECKME: Should we count proposers that didn't converge to our consensus set? - theApp->getOPs().newLCL(mPeerPositions.size(), mCurrentMSeconds, mNewLedgerHash); + // nothing to do } void LedgerConsensus::stateAccepted() @@ -770,6 +768,7 @@ void LedgerConsensus::beginAccept() return; } + theApp->getOPs().newLCL(mPeerPositions.size(), mCurrentMSeconds, mNewLedgerHash); boost::thread thread(boost::bind(&LedgerConsensus::Saccept, shared_from_this(), consensusSet)); thread.detach(); } From 524e89f4e1ce0452fea0d40b6e4a949c910a75a4 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 13 Aug 2012 17:35:20 -0700 Subject: [PATCH 09/20] Timing cleanups. --- src/LedgerTiming.h | 9 +++++++-- src/ValidationCollection.cpp | 11 ++++------- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/LedgerTiming.h b/src/LedgerTiming.h index 41e85762a1..9f5cfa903f 100644 --- a/src/LedgerTiming.h +++ b/src/LedgerTiming.h @@ -4,8 +4,13 @@ // The number of seconds a ledger may remain idle before closing # define LEDGER_IDLE_INTERVAL 15 -// The number of seconds a validation remains current -# define LEDGER_MAX_INTERVAL (LEDGER_IDLE_INTERVAL * 4) +// The number of seconds a validation remains current after its ledger's close time +// This is a safety to protect against very old validations +# define LEDGER_MAX_INTERVAL (LEDGER_IDLE_INTERVAL * 32) + +// The number of seconds before a close time that we consider a validation acceptable +// This protects against extreme clock errors +# define LEDGER_EARLY_INTERVAL 240 // The number of milliseconds we wait minimum to ensure participation # define LEDGER_MIN_CONSENSUS 2000 diff --git a/src/ValidationCollection.cpp b/src/ValidationCollection.cpp index 466b3d7f2e..68c54fc86e 100644 --- a/src/ValidationCollection.cpp +++ b/src/ValidationCollection.cpp @@ -14,7 +14,7 @@ bool ValidationCollection::addValidation(SerializedValidation::pointer val) val->setTrusted(); uint32 now = theApp->getOPs().getCloseTimeNC(); uint32 valClose = val->getCloseTime(); - if ((now > (valClose - 4)) && (now < (valClose + LEDGER_MAX_INTERVAL))) + if ((now > (valClose - LEDGER_EARLY_INTERVAL)) && (now < (valClose + LEDGER_MAX_INTERVAL))) isCurrent = true; else Log(lsWARNING) << "Received stale validation now=" << now << ", close=" << valClose; @@ -81,7 +81,7 @@ void ValidationCollection::getValidationCount(const uint256& ledger, bool curren if (isTrusted && currentOnly) { uint32 closeTime = vit->second->getCloseTime(); - if ((now < closeTime) || (now > (closeTime + 2 * LEDGER_MAX_INTERVAL))) + if ((now < (closeTime - LEDGER_EARLY_INTERVAL)) || (now > (closeTime + LEDGER_MAX_INTERVAL))) isTrusted = false; } if (isTrusted) @@ -129,7 +129,6 @@ boost::unordered_map ValidationCollection::getCurrentValidations() { boost::mutex::scoped_lock sl(mValidationLock); boost::unordered_map::iterator it = mCurrentValidations.begin(); - bool anyNew = false; while (it != mCurrentValidations.end()) { ValidationPair& pair = it->second; @@ -138,13 +137,13 @@ boost::unordered_map ValidationCollection::getCurrentValidations() { mStaleValidations.push_back(pair.oldest); pair.oldest = SerializedValidation::pointer(); - anyNew = true; + condWrite(); } if (pair.newest && (now > (pair.newest->getCloseTime() + LEDGER_MAX_INTERVAL))) { mStaleValidations.push_back(pair.newest); pair.newest = SerializedValidation::pointer(); - anyNew = true; + condWrite(); } if (!pair.newest && !pair.oldest) it = mCurrentValidations.erase(it); @@ -165,8 +164,6 @@ boost::unordered_map ValidationCollection::getCurrentValidations() ++it; } } - if (anyNew) - condWrite(); } return ret; From d1547998d71d7aa5640d248adc1754924b616fe0 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 13 Aug 2012 17:55:55 -0700 Subject: [PATCH 10/20] Change LEDGER_MAX_INTERVAL to LEDGER_VAL_INTERVAL to more accurately reflect what it now does. Turn this interval way up to ensure we can't lose synch (due to validations seeming too old) if time resolution drops drastically. --- src/LedgerTiming.h | 5 +++-- src/ValidationCollection.cpp | 8 ++++---- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/LedgerTiming.h b/src/LedgerTiming.h index 9f5cfa903f..eb8f2d56c8 100644 --- a/src/LedgerTiming.h +++ b/src/LedgerTiming.h @@ -5,8 +5,9 @@ # define LEDGER_IDLE_INTERVAL 15 // The number of seconds a validation remains current after its ledger's close time -// This is a safety to protect against very old validations -# define LEDGER_MAX_INTERVAL (LEDGER_IDLE_INTERVAL * 32) +// This is a safety to protect against very old validations and the time it takes to adjust +// the close time accuracy window +# define LEDGER_VAL_INTERVAL 600 // The number of seconds before a close time that we consider a validation acceptable // This protects against extreme clock errors diff --git a/src/ValidationCollection.cpp b/src/ValidationCollection.cpp index 68c54fc86e..41c772f819 100644 --- a/src/ValidationCollection.cpp +++ b/src/ValidationCollection.cpp @@ -14,7 +14,7 @@ bool ValidationCollection::addValidation(SerializedValidation::pointer val) val->setTrusted(); uint32 now = theApp->getOPs().getCloseTimeNC(); uint32 valClose = val->getCloseTime(); - if ((now > (valClose - LEDGER_EARLY_INTERVAL)) && (now < (valClose + LEDGER_MAX_INTERVAL))) + if ((now > (valClose - LEDGER_EARLY_INTERVAL)) && (now < (valClose + LEDGER_VAL_INTERVAL))) isCurrent = true; else Log(lsWARNING) << "Received stale validation now=" << now << ", close=" << valClose; @@ -81,7 +81,7 @@ void ValidationCollection::getValidationCount(const uint256& ledger, bool curren if (isTrusted && currentOnly) { uint32 closeTime = vit->second->getCloseTime(); - if ((now < (closeTime - LEDGER_EARLY_INTERVAL)) || (now > (closeTime + LEDGER_MAX_INTERVAL))) + if ((now < (closeTime - LEDGER_EARLY_INTERVAL)) || (now > (closeTime + LEDGER_VAL_INTERVAL))) isTrusted = false; } if (isTrusted) @@ -133,13 +133,13 @@ boost::unordered_map ValidationCollection::getCurrentValidations() { ValidationPair& pair = it->second; - if (pair.oldest && (now > (pair.oldest->getCloseTime() + LEDGER_MAX_INTERVAL))) + if (pair.oldest && (now > (pair.oldest->getCloseTime() + LEDGER_VAL_INTERVAL))) { mStaleValidations.push_back(pair.oldest); pair.oldest = SerializedValidation::pointer(); condWrite(); } - if (pair.newest && (now > (pair.newest->getCloseTime() + LEDGER_MAX_INTERVAL))) + if (pair.newest && (now > (pair.newest->getCloseTime() + LEDGER_VAL_INTERVAL))) { mStaleValidations.push_back(pair.newest); pair.newest = SerializedValidation::pointer(); From ba6e65214b6f7b789130be3f2cbe8916071e443e Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 13 Aug 2012 19:23:49 -0700 Subject: [PATCH 11/20] Log whether a ledger is alive or dead when considering it as LCL. --- src/NetworkOPs.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/NetworkOPs.cpp b/src/NetworkOPs.cpp index 875834a1e5..355318844c 100644 --- a/src/NetworkOPs.cpp +++ b/src/NetworkOPs.cpp @@ -458,9 +458,10 @@ bool NetworkOPs::checkLastClosedLedger(const std::vector& peerLis for (boost::unordered_map::iterator it = ledgers.begin(), end = ledgers.end(); it != end; ++it) { - Log(lsTRACE) << "L: " << it->first.GetHex() << + bool isDead = theApp->getValidations().isDeadLedger(it->first); + Log(lsTRACE) << "L: " << it->first.GetHex() << ((isDead) ? " dead" : " live") << " t=" << it->second.trustedValidations << ", n=" << it->second.nodesUsing; - if ((it->second > bestVC) && !theApp->getValidations().isDeadLedger(it->first)) + if ((it->second > bestVC) && !isDead) { bestVC = it->second; closedLedger = it->first; From 8068e5fbb9b699a300cf4b8898cb840af8c11143 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 13 Aug 2012 22:27:20 -0700 Subject: [PATCH 12/20] Remove chatty debug. --- src/ValidationCollection.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ValidationCollection.cpp b/src/ValidationCollection.cpp index 41c772f819..2f29327140 100644 --- a/src/ValidationCollection.cpp +++ b/src/ValidationCollection.cpp @@ -151,13 +151,13 @@ boost::unordered_map ValidationCollection::getCurrentValidations() { if (pair.oldest) { - Log(lsTRACE) << "OLD " << pair.oldest->getLedgerHash().GetHex() << " " << +// Log(lsTRACE) << "OLD " << pair.oldest->getLedgerHash().GetHex() << " " << boost::lexical_cast(pair.oldest->getCloseTime()); ++ret[pair.oldest->getLedgerHash()]; } if (pair.newest) { - Log(lsTRACE) << "NEW " << pair.newest->getLedgerHash().GetHex() << " " << +// Log(lsTRACE) << "NEW " << pair.newest->getLedgerHash().GetHex() << " " << boost::lexical_cast(pair.newest->getCloseTime()); ++ret[pair.newest->getLedgerHash()]; } From 22237e58ab15a02b257f072c854101dc9f32b9ca Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 13 Aug 2012 22:27:29 -0700 Subject: [PATCH 13/20] Check for network condition during idle time. Switch LCL if needed. --- src/LedgerConsensus.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index a2888f190a..6b56b66402 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -224,7 +224,7 @@ LedgerConsensus::LedgerConsensus(const uint256& prevLCLHash, Ledger::pointer pre } else { - Log(lsINFO) << "Entering consensus process, proposing"; + Log(lsINFO) << "Entering consensus process, watching"; mHaveCorrectLCL = true; mProposing = mValidating = false; } @@ -249,6 +249,9 @@ void LedgerConsensus::checkLCL() mPrevLedgerHash = netLgr; mAcquiringLedger = theApp->getMasterLedgerAcquire().findCreate(mPrevLedgerHash); std::vector peerList = theApp->getConnectionPool().getPeerVector(); + mHaveCorrectLCL = false; + mProposing = false; + mValidating = false; bool found = false; for (std::vector::const_iterator it = peerList.begin(), end = peerList.end(); it != end; ++it) if ((*it)->hasLedger(mPrevLedgerHash)) @@ -418,6 +421,8 @@ void LedgerConsensus::statePreClose() statusChange(newcoin::neCLOSING_LEDGER, *mPreviousLedger); takeInitialPosition(*theApp->getMasterLedger().closeLedger()); } + else + checkLCL(); } void LedgerConsensus::stateEstablish() From 6788105b2c72d8b154441e3d0b5b7e90fcebb791 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 13 Aug 2012 23:13:01 -0700 Subject: [PATCH 14/20] Chatty debug. --- src/HashedObject.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/HashedObject.cpp b/src/HashedObject.cpp index 9dc7e6e92c..71730bfb19 100644 --- a/src/HashedObject.cpp +++ b/src/HashedObject.cpp @@ -21,7 +21,9 @@ bool HashedObjectStore::store(HashedObjectType type, uint32 index, if (!theApp->getHashNodeDB()) return true; if (mCache.touch(hash)) { +#ifdef HS_DEBUG Log(lsTRACE) << "HOS: " << hash.GetHex() << " store: incache"; +#endif return false; } From 5eca52497f680377e90a7c5c28cc8942fab35b7e Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 13 Aug 2012 23:13:12 -0700 Subject: [PATCH 15/20] Improve close time synch with no transactions --- src/LedgerConsensus.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index 6b56b66402..aba77ea75f 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -408,7 +408,12 @@ void LedgerConsensus::statePreClose() int proposersClosed = mPeerPositions.size(); // This ledger is open. This computes how long since the last ledger closed - int sinceClose = 1000 * (theApp->getOPs().getCloseTimeNC() - theApp->getOPs().getLastCloseNetTime()); + int lastCloseTime; + if (!anyTransactions && mPreviousLedger->getCloseAgree()) + lastCloseTime = mPreviousLedger->getCloseTimeNC(); + else + lastCloseTime = theApp->getOPs().getLastCloseNetTime(); + int sinceClose = 1000 * (theApp->getOPs().getCloseTimeNC() - lastCloseTime); if (sinceClose >= ContinuousLedgerTiming::shouldClose(anyTransactions, mPreviousProposers, proposersClosed, mPreviousMSeconds, sinceClose)) @@ -911,12 +916,12 @@ void LedgerConsensus::accept(SHAMap::pointer set) SerializedValidation::pointer v = boost::make_shared (newLCLHash, newLCL->getCloseTimeNC(), mValSeed, mProposing); v->setTrusted(); + Log(lsINFO) << "CNF Val " << newLCLHash.GetHex(); theApp->getValidations().addValidation(v); std::vector validation = v->getSigned(); newcoin::TMValidation val; val.set_validation(&validation[0], validation.size()); theApp->getConnectionPool().relayMessage(NULL, boost::make_shared(val, newcoin::mtVALIDATION)); - Log(lsINFO) << "CNF Val " << newLCLHash.GetHex(); } else Log(lsINFO) << "CNF newLCL " << newLCLHash.GetHex(); From 227754496e0b995b9920fd80bffa5baff9b0b8b2 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 13 Aug 2012 23:14:39 -0700 Subject: [PATCH 16/20] Fix what is probably *the* bug. We aren't usually in our own UNL, so we specially mark our validations trusted. But that wasn't properly taken into account in one case where we decide if a validation is current. This causes two nodes to each not recognize their own validations, so they tend to exchange ledgers. Cleanups, extra logging. --- src/ValidationCollection.cpp | 34 +++++++++++++++++++++++++++------- src/ValidationCollection.h | 2 +- 2 files changed, 28 insertions(+), 8 deletions(-) diff --git a/src/ValidationCollection.cpp b/src/ValidationCollection.cpp index 2f29327140..1502e4b52d 100644 --- a/src/ValidationCollection.cpp +++ b/src/ValidationCollection.cpp @@ -5,11 +5,13 @@ #include "LedgerTiming.h" #include "Log.h" -bool ValidationCollection::addValidation(SerializedValidation::pointer val) +// #define VC_DEBUG + +bool ValidationCollection::addValidation(SerializedValidation::pointer& val) { NewcoinAddress signer = val->getSignerPublic(); bool isCurrent = false; - if (theApp->getUNL().nodeInUNL(signer)) + if (theApp->getUNL().nodeInUNL(signer) || val->isTrusted()) { val->setTrusted(); uint32 now = theApp->getOPs().getCloseTimeNC(); @@ -51,7 +53,7 @@ bool ValidationCollection::addValidation(SerializedValidation::pointer val) } Log(lsINFO) << "Val for " << hash.GetHex() << " from " << signer.humanNodePublic() - << " added " << (val->isTrusted() ? "trusted" : "UNtrusted"); + << " added " << (val->isTrusted() ? "trusted/" : "UNtrusted/") << (isCurrent ? "current" : "stale"); return isCurrent; } @@ -83,6 +85,12 @@ void ValidationCollection::getValidationCount(const uint256& ledger, bool curren uint32 closeTime = vit->second->getCloseTime(); if ((now < (closeTime - LEDGER_EARLY_INTERVAL)) || (now > (closeTime + LEDGER_VAL_INTERVAL))) isTrusted = false; + else + { +#ifdef VC_DEBUG + Log(lsINFO) << "VC: Untrusted due to time " << ledger.GetHex(); +#endif + } } if (isTrusted) ++trusted; @@ -90,6 +98,9 @@ void ValidationCollection::getValidationCount(const uint256& ledger, bool curren ++untrusted; } } +#ifdef VC_DEBUG + Log(lsINFO) << "VC: " << ledger.GetHex() << "t:" << trusted << " u:" << untrusted; +#endif } int ValidationCollection::getTrustedValidationCount(const uint256& ledger) @@ -135,12 +146,18 @@ boost::unordered_map ValidationCollection::getCurrentValidations() if (pair.oldest && (now > (pair.oldest->getCloseTime() + LEDGER_VAL_INTERVAL))) { +#ifdef VC_DEBUG + Log(lsINFO) << "VC: " << it->first.GetHex() << " removeOldestStale"; +#endif mStaleValidations.push_back(pair.oldest); pair.oldest = SerializedValidation::pointer(); condWrite(); } if (pair.newest && (now > (pair.newest->getCloseTime() + LEDGER_VAL_INTERVAL))) { +#ifdef VC_DEBUG + Log(lsINFO) << "VC: " << it->first.GetHex() << " removeNewestStale"; +#endif mStaleValidations.push_back(pair.newest); pair.newest = SerializedValidation::pointer(); condWrite(); @@ -151,14 +168,18 @@ boost::unordered_map ValidationCollection::getCurrentValidations() { if (pair.oldest) { -// Log(lsTRACE) << "OLD " << pair.oldest->getLedgerHash().GetHex() << " " << +#ifdef VC_DEBUG + Log(lsTRACE) << "VC: OLD " << pair.oldest->getLedgerHash().GetHex() << " " << boost::lexical_cast(pair.oldest->getCloseTime()); +#endif ++ret[pair.oldest->getLedgerHash()]; } if (pair.newest) { -// Log(lsTRACE) << "NEW " << pair.newest->getLedgerHash().GetHex() << " " << +#ifdef VC_DEBUG + Log(lsTRACE) << "VC: NEW " << pair.newest->getLedgerHash().GetHex() << " " << boost::lexical_cast(pair.newest->getCloseTime()); +#endif ++ret[pair.newest->getLedgerHash()]; } ++it; @@ -224,8 +245,7 @@ void ValidationCollection::condWrite() void ValidationCollection::doWrite() { static boost::format insVal("INSERT INTO LedgerValidations " - "(LedgerHash,NodePubKey,Flags,CloseTime,Signature) VALUES " - "('%s','%s','%u','%u',%s);"); + "(LedgerHash,NodePubKey,Flags,CloseTime,Signature) VALUES ('%s','%s','%u','%u',%s);"); boost::mutex::scoped_lock sl(mValidationLock); assert(mWriting); diff --git a/src/ValidationCollection.h b/src/ValidationCollection.h index 2198a967fe..1ed522dc54 100644 --- a/src/ValidationCollection.h +++ b/src/ValidationCollection.h @@ -38,7 +38,7 @@ protected: public: ValidationCollection() : mWriting(false) { ; } - bool addValidation(SerializedValidation::pointer); + bool addValidation(SerializedValidation::pointer&); ValidationSet getValidations(const uint256& ledger); void getValidationCount(const uint256& ledger, bool currentOnly, int& trusted, int& untrusted); From 04427b4ad024bc2de694b6555a66a1095c5414ee Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 13 Aug 2012 23:15:50 -0700 Subject: [PATCH 17/20] Cleanups. --- src/NetworkOPs.cpp | 40 +++++++++++++++++++++++----------------- 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/src/NetworkOPs.cpp b/src/NetworkOPs.cpp index 355318844c..afbf87e32a 100644 --- a/src/NetworkOPs.cpp +++ b/src/NetworkOPs.cpp @@ -322,8 +322,11 @@ public: { if (trustedValidations > v.trustedValidations) return true; if (trustedValidations < v.trustedValidations) return false; - if (nodesUsing > v.nodesUsing) return true; - if (nodesUsing < v.nodesUsing) return false; + if (trustedValidations == 0) + { + if (nodesUsing > v.nodesUsing) return true; + if (nodesUsing < v.nodesUsing) return false; + } return highNode > v.highNode; } }; @@ -332,6 +335,7 @@ void NetworkOPs::checkState(const boost::system::error_code& result) { // Network state machine if (result == boost::asio::error::operation_aborted) return; + setStateTimer(); std::vector peerList = theApp->getConnectionPool().getPeerVector(); @@ -344,7 +348,6 @@ void NetworkOPs::checkState(const boost::system::error_code& result) Log(lsWARNING) << "Node count (" << peerList.size() << ") has fallen below quorum (" << theConfig.NETWORK_QUORUM << ")."; } - setStateTimer(); return; } if (mMode == omDISCONNECTED) @@ -356,7 +359,6 @@ void NetworkOPs::checkState(const boost::system::error_code& result) if (mConsensus) { mConsensus->timerEntry(); - setStateTimer(); return; } @@ -383,15 +385,13 @@ void NetworkOPs::checkState(const boost::system::error_code& result) // check if the ledger is good enough to go to omFULL // Note: Do not go to omFULL if we don't have the previous ledger // check if the ledger is bad enough to go to omCONNECTED -- TODO - if (theApp->getOPs().getNetworkTimeNC() < - (theApp->getMasterLedger().getCurrentLedger()->getCloseTimeNC() + 4)) + if (theApp->getOPs().getNetworkTimeNC() < theApp->getMasterLedger().getCurrentLedger()->getCloseTimeNC()) setMode(omFULL); - else - Log(lsINFO) << "Will try to go to FULL in consensus window"; } if (mMode == omFULL) { + // WRITEME // check if the ledger is bad enough to go to omTRACKING } @@ -399,7 +399,6 @@ void NetworkOPs::checkState(const boost::system::error_code& result) beginConsensus(networkClosed, theApp->getMasterLedger().getCurrentLedger()); if (mConsensus) mConsensus->timerEntry(); - setStateTimer(); } bool NetworkOPs::checkLastClosedLedger(const std::vector& peerList, uint256& networkClosed) @@ -460,7 +459,7 @@ bool NetworkOPs::checkLastClosedLedger(const std::vector& peerLis { bool isDead = theApp->getValidations().isDeadLedger(it->first); Log(lsTRACE) << "L: " << it->first.GetHex() << ((isDead) ? " dead" : " live") << - " t=" << it->second.trustedValidations << ", n=" << it->second.nodesUsing; + " t=" << it->second.trustedValidations << ", n=" << it->second.nodesUsing; if ((it->second > bestVC) && !isDead) { bestVC = it->second; @@ -633,20 +632,23 @@ bool NetworkOPs::recvPropose(uint32 proposeSeq, const uint256& proposeHash, uint SHAMap::pointer NetworkOPs::getTXMap(const uint256& hash) { - if (!mConsensus) return SHAMap::pointer(); + if (!mConsensus) + return SHAMap::pointer(); return mConsensus->getTransactionTree(hash, false); } bool NetworkOPs::gotTXData(boost::shared_ptr peer, const uint256& hash, const std::list& nodeIDs, const std::list< std::vector >& nodeData) { - if (!mConsensus) return false; + if (!mConsensus) + return false; return mConsensus->peerGaveNodes(peer, hash, nodeIDs, nodeData); } bool NetworkOPs::hasTXSet(boost::shared_ptr peer, const uint256& set, newcoin::TxSetStatus status) { - if (!mConsensus) return false; + if (!mConsensus) + return false; return mConsensus->peerHasSet(peer, set, status); } @@ -677,10 +679,14 @@ void NetworkOPs::setMode(OperatingMode om) if ((om >= omCONNECTED) && (mMode == omDISCONNECTED)) mConnectTime = boost::posix_time::second_clock::universal_time(); Log l((om < mMode) ? lsWARNING : lsINFO); - if (om == omDISCONNECTED) l << "STATE->Disonnected"; - else if (om == omCONNECTED) l << "STATE->Connected"; - else if (om == omTRACKING) l << "STATE->Tracking"; - else l << "STATE->Full"; + if (om == omDISCONNECTED) + l << "STATE->Disonnected"; + else if (om == omCONNECTED) + l << "STATE->Connected"; + else if (om == omTRACKING) + l << "STATE->Tracking"; + else + l << "STATE->Full"; mMode = om; } From 3dcdc3b94a449c7b506b02d917a706e5df2b0508 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Tue, 14 Aug 2012 01:51:17 -0700 Subject: [PATCH 18/20] Fire up the aux thread earlier. --- src/Application.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Application.cpp b/src/Application.cpp index daac98dd54..af3b17f9a0 100644 --- a/src/Application.cpp +++ b/src/Application.cpp @@ -70,11 +70,11 @@ void Application::run() if (!theConfig.DEBUG_LOGFILE.empty()) Log::setLogFile(theConfig.DEBUG_LOGFILE); - mSNTPClient.init(theConfig.SNTP_SERVERS); - boost::thread auxThread(boost::bind(&boost::asio::io_service::run, &mAuxService)); auxThread.detach(); + mSNTPClient.init(theConfig.SNTP_SERVERS); + // // Construct databases. // From 046c539d49f0e8cb0b262c08d337cdd1f80040f2 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Tue, 14 Aug 2012 01:51:35 -0700 Subject: [PATCH 19/20] Mark a parameter as unused. --- src/Ledger.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Ledger.cpp b/src/Ledger.cpp index 131e7d3b91..0cd6e2346d 100644 --- a/src/Ledger.cpp +++ b/src/Ledger.cpp @@ -57,7 +57,7 @@ Ledger::Ledger(Ledger& ledger, bool isMutable) : mTotCoins(ledger.mTotCoins), mL } -Ledger::Ledger(bool dummy, Ledger& prevLedger) : +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), From 4b2ae556bd29fc31988ed595b8667b530ffbc96f Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Tue, 14 Aug 2012 01:51:46 -0700 Subject: [PATCH 20/20] Downgrade a timing issue from fatal to warning. --- src/LedgerTiming.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/LedgerTiming.cpp b/src/LedgerTiming.cpp index ae0d65de19..9243dd6ce0 100644 --- a/src/LedgerTiming.cpp +++ b/src/LedgerTiming.cpp @@ -22,8 +22,8 @@ int ContinuousLedgerTiming::shouldClose( if ((previousMSeconds < -1000) || (previousMSeconds > 600000) || (currentMSeconds < -1000) || (currentMSeconds > 600000)) { - Log(lsFATAL) << - boost::str(boost::format("CLC::shouldClose range error Trans=%s, Prop: %d/%d, Secs: %d (last:%d)") + Log(lsWARNING) << + boost::str(boost::format("CLC::shouldClose range Trans=%s, Prop: %d/%d, Secs: %d (last:%d)") % (anyTransactions ? "yes" : "no") % previousProposers % proposersClosed % currentMSeconds % previousMSeconds); return currentMSeconds;