diff --git a/src/cpp/ripple/FeatureTable.cpp b/src/cpp/ripple/FeatureTable.cpp index ebf4d268b..e5652a758 100644 --- a/src/cpp/ripple/FeatureTable.cpp +++ b/src/cpp/ripple/FeatureTable.cpp @@ -1,5 +1,11 @@ #include "FeatureTable.h" +#include + +#include "Log.h" + +SETUP_LOG(); + FeatureTable::FeatureState* FeatureTable::getCreateFeature(const uint256& feature, bool create) { // call with the mutex held featureMap_t::iterator it = mFeatureMap.find(feature); @@ -59,3 +65,113 @@ bool FeatureTable::isFeatureEnabled(const uint256& feature) return s && s->mEnabled; } +FeatureTable::featureList_t FeatureTable::getVetoedFeatures() +{ + featureList_t ret; + boost::mutex::scoped_lock sl(mMutex); + BOOST_FOREACH(const featureIt_t& it, mFeatureMap) + { + if (it.second.mVetoed) + ret.insert(it.first); + } + return ret; +} + +FeatureTable::featureList_t FeatureTable::getEnabledFeatures() +{ + featureList_t ret; + boost::mutex::scoped_lock sl(mMutex); + BOOST_FOREACH(const featureIt_t& it, mFeatureMap) + { + if (it.second.mEnabled) + ret.insert(it.first); + } + return ret; +} + +bool FeatureTable::shouldEnable(uint32 closeTime, const FeatureState& fs) +{ + if (fs.mVetoed || fs.mEnabled || (fs.mLastMajority != mLastReport)) + return false; + + if (fs.mFirstMajority == mFirstReport) + { // had a majority when we first started the server, relaxed check + // WRITEME + } + else + { // didn't have a majority when we first started the server, normal check + // WRITEME + } + + return true; + +} + +FeatureTable::featureList_t FeatureTable::getFeaturesToEnable(uint32 closeTime) +{ + featureList_t ret; + boost::mutex::scoped_lock sl(mMutex); + if (mLastReport != 0) + { + BOOST_FOREACH(const featureIt_t& it, mFeatureMap) + { + if (shouldEnable(closeTime, it.second)) + ret.insert(it.first); + } + } + return ret; +} + +void FeatureTable::reportValidations(const FeatureSet& set) +{ + if (set.mTrustedValidations == 0) + return; + int threshold = (set.mTrustedValidations * mMajorityFraction) / 256; + + typedef std::pair u256_int_pair; + + boost::mutex::scoped_lock sl(mMutex); + + if (mFirstReport == 0) + mFirstReport = set.mCloseTime; + BOOST_FOREACH(const u256_int_pair& it, set.mVotes) + { + FeatureState& state = mFeatureMap[it.first]; + cLog(lsDEBUG) << "Feature " << it.first.GetHex() << " has " << it.second << " votes, needs " << threshold; + if (it.second >= threshold) + { // we have a majority + state.mLastMajority = set.mCloseTime; + if (state.mFirstMajority == 0) + { + cLog(lsWARNING) << "Feature " << it.first << " attains a majority vote"; + state.mFirstMajority = set.mCloseTime; + } + } + else // we have no majority + { + if (state.mFirstMajority != 0) + { + cLog(lsWARNING) << "Feature " << it.first << " loses majority vote"; + state.mFirstMajority = 0; + state.mLastMajority = 0; + } + } + } + mLastReport = set.mCloseTime; +} + +Json::Value FeatureTable::getJson(int) +{ + Json::Value ret(Json::objectValue); + { + boost::mutex::scoped_lock sl(mMutex); + BOOST_FOREACH(const featureIt_t& it, mFeatureMap) + { + Json::Value v(Json::objectValue); + // WRITEME + ret[it.first.GetHex()] = v; + } + } + + return ret; +} diff --git a/src/cpp/ripple/FeatureTable.h b/src/cpp/ripple/FeatureTable.h index fa268700a..4fba5a276 100644 --- a/src/cpp/ripple/FeatureTable.h +++ b/src/cpp/ripple/FeatureTable.h @@ -5,15 +5,19 @@ #include #include +#include "../json/value.h" + #include "uint256.h" -struct FeatureSet +class FeatureSet { // the status of all features requested in a given window - uint32 mLedgerSequence; +public: uint32 mCloseTime; int mTrustedValidations; // number of trusted validations - boost::unordered_map mVotes; // yes votes by feature + + FeatureSet(uint32 ct, int tv) : mCloseTime(ct), mTrustedValidations(tv) { ; } + void addVote(const uint256& feature) { ++mVotes[feature]; } }; class FeatureTable @@ -26,28 +30,31 @@ protected: bool mVetoed; // We don't want this feature enabled bool mEnabled; - int mEnableVotes; // Trusted votes to enable this feature - int mDisableVotes; // Trusted votes to disable this feature - uint32 mFirstMajority; // First time we saw a majority (ledger sequence) - uint32 mLastMajority; // Most recent time we saw a majority + 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), mEnableVotes(0), mDisableVotes(0), - mFirstMajority(0), mLastMajority(0) { ; } + FeatureState() : mVetoed(false), mEnabled(false), mFirstMajority(0), mLastMajority(0) { ; } }; typedef boost::unordered_map featureMap_t; + typedef std::pair featureIt_t; typedef boost::unordered_set featureList_t; boost::mutex mMutex; featureMap_t mFeatureMap; int mMajorityTime; // Seconds a feature must hold a majority int mMajorityFraction; // 256 = 100% + uint32 mFirstReport; // close time of first majority report + uint32 mLastReport; // close time of most recent majority report FeatureState* getCreateFeature(const uint256& feature, bool create); + bool shouldEnable (uint32 closeTime, const FeatureState& fs); public: - FeatureTable(uint32 majorityTime, int mMajorityFraction) : mMajorityTime(majorityTime) { ; } + FeatureTable(uint32 majorityTime, int majorityFraction) + : mMajorityTime(majorityTime), mMajorityFraction(majorityFraction), mFirstReport(0) + { ; } bool vetoFeature(const uint256& feature); bool unVetoFeature(const uint256& feature); @@ -59,9 +66,11 @@ public: featureList_t getVetoedFeatures(); featureList_t getEnabledFeatures(); - featureList_t getFeaturesToEnable(uint32 sequence); // gets features we would vote to enable + featureList_t getFeaturesToEnable(uint32 closeTime); // gets features we would vote to enable void reportValidations(const FeatureSet&); + + Json::Value getJson(int); }; #endif