From 0bcd2eb09a195f24e041416d734ea2e7b12b2352 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Wed, 29 May 2013 11:54:20 -0700 Subject: [PATCH 1/5] Static feature support. --- src/cpp/ripple/Application.cpp | 2 ++ src/cpp/ripple/FeatureTable.cpp | 6 +++--- src/cpp/ripple/FeatureTable.h | 34 ++++++++++++++++++++------------- 3 files changed, 26 insertions(+), 16 deletions(-) diff --git a/src/cpp/ripple/Application.cpp b/src/cpp/ripple/Application.cpp index fcd0a6d07..9c5bc7712 100644 --- a/src/cpp/ripple/Application.cpp +++ b/src/cpp/ripple/Application.cpp @@ -431,6 +431,8 @@ void Application::startNewLedger() { Ledger::pointer firstLedger = boost::make_shared(rootAddress, SYSTEM_CURRENCY_START); assert(!!firstLedger->getAccountState(rootAddress)); + // WRITEME: Add any default features + // WRITEME: Set default fee/reserve firstLedger->updateHash(); firstLedger->setClosed(); firstLedger->setAccepted(); diff --git a/src/cpp/ripple/FeatureTable.cpp b/src/cpp/ripple/FeatureTable.cpp index e76e7cb15..eff8a8be2 100644 --- a/src/cpp/ripple/FeatureTable.cpp +++ b/src/cpp/ripple/FeatureTable.cpp @@ -3,11 +3,11 @@ SETUP_LOG (FeatureTable) void FeatureTable::addInitialFeatures() { - // For each feature this version supports, call enableFeature. - // Permanent vetos can also be added here. + // For each feature this version supports, construct the FeatureState object by calling + // getCreateFeature. Set any vetoes or defaults. A pointer to the FeatureState can be stashed } -FeatureTable::FeatureState* FeatureTable::getCreateFeature(const uint256& featureHash, bool create) +FeatureState* FeatureTable::getCreateFeature(const uint256& featureHash, bool create) { // call with the mutex held featureMap_t::iterator it = mFeatureMap.find(featureHash); if (it == mFeatureMap.end()) diff --git a/src/cpp/ripple/FeatureTable.h b/src/cpp/ripple/FeatureTable.h index 9579f4019..79c9f1f65 100644 --- a/src/cpp/ripple/FeatureTable.h +++ b/src/cpp/ripple/FeatureTable.h @@ -18,23 +18,31 @@ public: void addVote(const uint256& feature) { ++mVotes[feature]; } }; +class FeatureState +{ +public: + uint256 mHash; // Feature hash + bool mVetoed; // We don't want this feature enabled + bool mEnabled; + bool mSupported; + bool mDefault; // Include in genesis ledger + + uint32 mFirstMajority; // First time we saw a majority (close time) + uint32 mLastMajority; // Most recent time we saw a majority (close time) + + FeatureState() + : mVetoed(false), mEnabled(false), mSupported(false), mDefault(false), + mFirstMajority(0), mLastMajority(0) { ; } + + void setVeto() { mVetoed = true; } + void setDefault() { mDefault = true; } +}; + + class FeatureTable { protected: - class FeatureState - { - public: - bool mVetoed; // We don't want this feature enabled - bool mEnabled; - bool mSupported; - - uint32 mFirstMajority; // First time we saw a majority (close time) - uint32 mLastMajority; // Most recent time we saw a majority (close time) - - FeatureState() : mVetoed(false), mEnabled(false), mSupported(false), mFirstMajority(0), mLastMajority(0) { ; } - }; - typedef boost::unordered_map featureMap_t; typedef std::pair featureIt_t; typedef boost::unordered_set featureList_t; From 8781e131c5787f2ea32f0f3640fca0d9158fdd28 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Wed, 29 May 2013 13:04:05 -0700 Subject: [PATCH 2/5] Write back feature majority times. Mark a FIXME. --- src/cpp/ripple/FeatureTable.cpp | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/src/cpp/ripple/FeatureTable.cpp b/src/cpp/ripple/FeatureTable.cpp index eff8a8be2..d787f8326 100644 --- a/src/cpp/ripple/FeatureTable.cpp +++ b/src/cpp/ripple/FeatureTable.cpp @@ -193,7 +193,22 @@ void FeatureTable::reportValidations(const FeatureSet& set) if (!changedFeatures.empty()) { - // WRITEME write changed features to SQL db + ScopedLock sl(theApp->getWalletDB()->getDBLock()); + Database* db = theApp->getWalletDB()->getDB(); + + db->executeSQL("BEGIN TRANSACTION;"); + BOOST_FOREACH(const uint256& hash, changedFeatures) + { + FeatureState& fState = mFeatureMap[hash]; + db->executeSQL(boost::str(boost::format( + "UPDATE Features SET FirstMajority = %d WHERE Hash = '%s';" + ) % fState.mFirstMajority % hash.GetHex())); + db->executeSQL(boost::str(boost::format( + "UPDATE Features SET LastMajority = %d WHERE Hash = '%s';" + ) % fState.mLastMajority % hash.GetHex())); + } + db->executeSQL("END TRANSACTION;"); + changedFeatures.clear(); } } @@ -246,12 +261,12 @@ void FeatureTable::doVoting(Ledger::ref lastClosedLedger, SHAMap::ref initialPos BOOST_FOREACH(const uint256& uFeature, lFeatures) { - WriteLog (lsWARNING, FeatureTable) << "We are voting for feature " << uFeature; + WriteLog (lsWARNING, FeatureTable) << "Voting for feature: " << uFeature; SerializedTransaction trans(ttFEATURE); trans.setFieldAccount(sfAccount, uint160()); trans.setFieldH256(sfFeature, uFeature); uint256 txID = trans.getTransactionID(); - WriteLog (lsWARNING, FeatureTable) << "Vote: " << txID; + WriteLog (lsWARNING, FeatureTable) << "Vote ID: " << txID; Serializer s; trans.add(s, true); @@ -271,7 +286,7 @@ Json::Value FeatureTable::getJson(int) boost::mutex::scoped_lock sl(mMutex); BOOST_FOREACH(const featureIt_t& it, mFeatureMap) { - Json::Value v(Json::objectValue); + Json::Value& v(ret[it.first.GetHex()] = Json::objectValue); v["supported"] = it.second.mSupported; @@ -283,7 +298,9 @@ Json::Value FeatureTable::getJson(int) if (mLastReport != 0) { if (it.second.mLastMajority == 0) + { v["majority"] = false; + } else { if (it.second.mFirstMajority != 0) @@ -306,8 +323,6 @@ Json::Value FeatureTable::getJson(int) if (it.second.mVetoed) v["veto"] = true; - - ret[it.first.GetHex()] = v; } } @@ -350,6 +365,7 @@ public: typedef typename std::map::value_type mapVType; BOOST_FOREACH(const mapVType& value, mVoteMap) { // Take most voted value between current and target, inclusive + // FIXME: Should take best value that can get a significant majority if ((value.first <= std::max(mTarget, mCurrent)) && (value.first >= std::min(mTarget, mCurrent)) && (value.second > weight)) From f716fe2cab07b27d60781d4f0180d6536c9da1b6 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Wed, 29 May 2013 16:18:56 -0700 Subject: [PATCH 3/5] RPC infrastructure for feature management. --- src/cpp/ripple/CallRPC.cpp | 15 +++++++++++++++ src/cpp/ripple/CallRPC.h | 1 + src/cpp/ripple/FeatureTable.cpp | 4 ++++ src/cpp/ripple/RPCHandler.cpp | 19 +++++++++++++++++++ src/cpp/ripple/RPCHandler.h | 1 + 5 files changed, 40 insertions(+) diff --git a/src/cpp/ripple/CallRPC.cpp b/src/cpp/ripple/CallRPC.cpp index 3193e3683..27a7e0144 100644 --- a/src/cpp/ripple/CallRPC.cpp +++ b/src/cpp/ripple/CallRPC.cpp @@ -311,6 +311,20 @@ Json::Value RPCParser::parseEvented(const Json::Value& jvParams) return rpcError(rpcNO_EVENTS); } +// feature [] [true|false] +Json::Value RPCParser::parseFeature(const Json::Value& jvParams) +{ + Json::Value jvRequest(Json::objectValue); + + if (jvParams.size() > 0) + jvRequest["feature"] = jvParams[0u].asString(); + + if (jvParams.size() > 1) + jvRequest["vote"] = boost::lexical_cast(jvParams[1u].asString()); + + return jvRequest; +} + // get_counts [] Json::Value RPCParser::parseGetCounts(const Json::Value& jvParams) { @@ -734,6 +748,7 @@ Json::Value RPCParser::parseCommand(std::string strMethod, Json::Value jvParams) { "book_offers", &RPCParser::parseBookOffers, 2, 7 }, { "connect", &RPCParser::parseConnect, 1, 2 }, { "consensus_info", &RPCParser::parseAsIs, 0, 0 }, + { "feature", &RPCParser::parseFeature, 0, 2 }, { "get_counts", &RPCParser::parseGetCounts, 0, 1 }, { "json", &RPCParser::parseJson, 2, 2 }, { "ledger", &RPCParser::parseLedger, 0, 2 }, diff --git a/src/cpp/ripple/CallRPC.h b/src/cpp/ripple/CallRPC.h index 3ce69167a..0ce9a8630 100644 --- a/src/cpp/ripple/CallRPC.h +++ b/src/cpp/ripple/CallRPC.h @@ -22,6 +22,7 @@ protected: Json::Value parseDataStore(const Json::Value& jvParams); #endif Json::Value parseEvented(const Json::Value& jvParams); + Json::Value parseFeature(const Json::Value& jvParams); Json::Value parseGetCounts(const Json::Value& jvParams); Json::Value parseInternal(const Json::Value& jvParams); Json::Value parseJson(const Json::Value& jvParams); diff --git a/src/cpp/ripple/FeatureTable.cpp b/src/cpp/ripple/FeatureTable.cpp index d787f8326..e93a5821b 100644 --- a/src/cpp/ripple/FeatureTable.cpp +++ b/src/cpp/ripple/FeatureTable.cpp @@ -1,10 +1,14 @@ SETUP_LOG (FeatureTable) +FeatureState* testFeature = NULL; + void FeatureTable::addInitialFeatures() { // For each feature this version supports, construct the FeatureState object by calling // getCreateFeature. Set any vetoes or defaults. A pointer to the FeatureState can be stashed + + testFeature = getCreateFeature(uint256("1234"), true); } FeatureState* FeatureTable::getCreateFeature(const uint256& featureHash, bool create) diff --git a/src/cpp/ripple/RPCHandler.cpp b/src/cpp/ripple/RPCHandler.cpp index 49755949e..d79232aff 100644 --- a/src/cpp/ripple/RPCHandler.cpp +++ b/src/cpp/ripple/RPCHandler.cpp @@ -2265,6 +2265,24 @@ static void textTime(std::string& text, int& seconds, const char *unitName, int text += "s"; } +Json::Value RPCHandler::doFeature(Json::Value jvRequest, int& cost, ScopedLock& mlh) +{ + if (!jvRequest.isMember("feature")) + { + Json::Value jvReply = Json::objectValue; + jvReply["features"] = theApp->getFeatureTable().getJson(0); + return jvReply; + } + + if (!jvRequest.isMember("vote")) + { + // WRITEME + } + + // WRITEME + return rpcError(rpcNOT_SUPPORTED); +} + // { // min_count: // optional, defaults to 10 // } @@ -3471,6 +3489,7 @@ Json::Value RPCHandler::doCommand(const Json::Value& jvRequest, int iRole, int & { "consensus_info", &RPCHandler::doConsensusInfo, true, optNone }, { "get_counts", &RPCHandler::doGetCounts, true, optNone }, { "internal", &RPCHandler::doInternal, true, optNone }, + { "feature", &RPCHandler::doFeature, true, optNone }, { "ledger", &RPCHandler::doLedger, false, optNetwork }, { "ledger_accept", &RPCHandler::doLedgerAccept, true, optCurrent }, { "ledger_closed", &RPCHandler::doLedgerClosed, false, optClosed }, diff --git a/src/cpp/ripple/RPCHandler.h b/src/cpp/ripple/RPCHandler.h index ed3fd12a2..849aaf0eb 100644 --- a/src/cpp/ripple/RPCHandler.h +++ b/src/cpp/ripple/RPCHandler.h @@ -59,6 +59,7 @@ class RPCHandler Json::Value doDataFetch(Json::Value params, int& cost, ScopedLock& mlh); Json::Value doDataStore(Json::Value params, int& cost, ScopedLock& mlh); #endif + Json::Value doFeature(Json::Value params, int& cost, ScopedLock& mlh); Json::Value doGetCounts(Json::Value params, int& cost, ScopedLock& mlh); Json::Value doInternal(Json::Value params, int& cost, ScopedLock& mlh); Json::Value doLedger(Json::Value params, int& cost, ScopedLock& mlh); From f3b04e666110405f3292491a45383f4288e99df8 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Wed, 29 May 2013 16:46:28 -0700 Subject: [PATCH 4/5] Bugfix. --- src/cpp/ripple/Application.cpp | 2 ++ src/cpp/ripple/FeatureTable.h | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/cpp/ripple/Application.cpp b/src/cpp/ripple/Application.cpp index 6e2140e95..c1ccf84c4 100644 --- a/src/cpp/ripple/Application.cpp +++ b/src/cpp/ripple/Application.cpp @@ -201,6 +201,8 @@ void Application::setup() if (!theConfig.RUN_STANDALONE) updateTables(theConfig.LDB_IMPORT); + mFeatureTable.addInitialFeatures(); + if (theConfig.START_UP == Config::FRESH) { WriteLog (lsINFO, Application) << "Starting new Ledger"; diff --git a/src/cpp/ripple/FeatureTable.h b/src/cpp/ripple/FeatureTable.h index 79c9f1f65..aecc60b19 100644 --- a/src/cpp/ripple/FeatureTable.h +++ b/src/cpp/ripple/FeatureTable.h @@ -61,7 +61,7 @@ public: FeatureTable(uint32 majorityTime, int majorityFraction) : mMajorityTime(majorityTime), mMajorityFraction(majorityFraction), mFirstReport(0), mLastReport(0) - { addInitialFeatures(); } + { ; } void addInitialFeatures(); From b66e06369086e287582910d889e8e4a10dbfbb1a Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Thu, 30 May 2013 10:09:20 -0700 Subject: [PATCH 5/5] Updates --- src/cpp/ripple/FeatureTable.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/cpp/ripple/FeatureTable.h b/src/cpp/ripple/FeatureTable.h index aecc60b19..b91523211 100644 --- a/src/cpp/ripple/FeatureTable.h +++ b/src/cpp/ripple/FeatureTable.h @@ -36,6 +36,10 @@ public: void setVeto() { mVetoed = true; } void setDefault() { mDefault = true; } + bool isDefault() { return mDefault; } + bool isSupported() { return mSupported; } + bool isVetoed() { return mVetoed; } + bool isEnabled() { return mEnabled; } };