mirror of
https://github.com/XRPLF/rippled.git
synced 2025-11-27 14:35:52 +00:00
Merge branch 'feature' into develop
This commit is contained in:
@@ -206,6 +206,8 @@ void Application::setup()
|
|||||||
if (!theConfig.RUN_STANDALONE)
|
if (!theConfig.RUN_STANDALONE)
|
||||||
updateTables(theConfig.LDB_IMPORT);
|
updateTables(theConfig.LDB_IMPORT);
|
||||||
|
|
||||||
|
mFeatureTable.addInitialFeatures();
|
||||||
|
|
||||||
if (theConfig.START_UP == Config::FRESH)
|
if (theConfig.START_UP == Config::FRESH)
|
||||||
{
|
{
|
||||||
WriteLog (lsINFO, Application) << "Starting new Ledger";
|
WriteLog (lsINFO, Application) << "Starting new Ledger";
|
||||||
@@ -437,6 +439,8 @@ void Application::startNewLedger()
|
|||||||
{
|
{
|
||||||
Ledger::pointer firstLedger = boost::make_shared<Ledger>(rootAddress, SYSTEM_CURRENCY_START);
|
Ledger::pointer firstLedger = boost::make_shared<Ledger>(rootAddress, SYSTEM_CURRENCY_START);
|
||||||
assert(!!firstLedger->getAccountState(rootAddress));
|
assert(!!firstLedger->getAccountState(rootAddress));
|
||||||
|
// WRITEME: Add any default features
|
||||||
|
// WRITEME: Set default fee/reserve
|
||||||
firstLedger->updateHash();
|
firstLedger->updateHash();
|
||||||
firstLedger->setClosed();
|
firstLedger->setClosed();
|
||||||
firstLedger->setAccepted();
|
firstLedger->setAccepted();
|
||||||
@@ -548,6 +552,12 @@ bool serverOkay(std::string& reason)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (theApp->getOPs().isFeatureBlocked())
|
||||||
|
{
|
||||||
|
reason = "Server version too old";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -310,6 +310,20 @@ Json::Value RPCParser::parseEvented(const Json::Value& jvParams)
|
|||||||
return rpcError(rpcNO_EVENTS);
|
return rpcError(rpcNO_EVENTS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// feature [<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<bool>(jvParams[1u].asString());
|
||||||
|
|
||||||
|
return jvRequest;
|
||||||
|
}
|
||||||
|
|
||||||
// get_counts [<min_count>]
|
// get_counts [<min_count>]
|
||||||
Json::Value RPCParser::parseGetCounts(const Json::Value& jvParams)
|
Json::Value RPCParser::parseGetCounts(const Json::Value& jvParams)
|
||||||
{
|
{
|
||||||
@@ -733,6 +747,7 @@ Json::Value RPCParser::parseCommand(std::string strMethod, Json::Value jvParams)
|
|||||||
{ "book_offers", &RPCParser::parseBookOffers, 2, 7 },
|
{ "book_offers", &RPCParser::parseBookOffers, 2, 7 },
|
||||||
{ "connect", &RPCParser::parseConnect, 1, 2 },
|
{ "connect", &RPCParser::parseConnect, 1, 2 },
|
||||||
{ "consensus_info", &RPCParser::parseAsIs, 0, 0 },
|
{ "consensus_info", &RPCParser::parseAsIs, 0, 0 },
|
||||||
|
{ "feature", &RPCParser::parseFeature, 0, 2 },
|
||||||
{ "get_counts", &RPCParser::parseGetCounts, 0, 1 },
|
{ "get_counts", &RPCParser::parseGetCounts, 0, 1 },
|
||||||
{ "json", &RPCParser::parseJson, 2, 2 },
|
{ "json", &RPCParser::parseJson, 2, 2 },
|
||||||
{ "ledger", &RPCParser::parseLedger, 0, 2 },
|
{ "ledger", &RPCParser::parseLedger, 0, 2 },
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ protected:
|
|||||||
Json::Value parseDataStore(const Json::Value& jvParams);
|
Json::Value parseDataStore(const Json::Value& jvParams);
|
||||||
#endif
|
#endif
|
||||||
Json::Value parseEvented(const Json::Value& jvParams);
|
Json::Value parseEvented(const Json::Value& jvParams);
|
||||||
|
Json::Value parseFeature(const Json::Value& jvParams);
|
||||||
Json::Value parseGetCounts(const Json::Value& jvParams);
|
Json::Value parseGetCounts(const Json::Value& jvParams);
|
||||||
Json::Value parseInternal(const Json::Value& jvParams);
|
Json::Value parseInternal(const Json::Value& jvParams);
|
||||||
Json::Value parseJson(const Json::Value& jvParams);
|
Json::Value parseJson(const Json::Value& jvParams);
|
||||||
|
|||||||
@@ -85,6 +85,10 @@ TER ChangeTransactor::applyFeature()
|
|||||||
featureObject->setFieldV256(sfFeatures, features);
|
featureObject->setFieldV256(sfFeatures, features);
|
||||||
mEngine->entryModify(featureObject);
|
mEngine->entryModify(featureObject);
|
||||||
|
|
||||||
|
theApp->getFeatureTable().enableFeature(feature);
|
||||||
|
if (!theApp->getFeatureTable().isFeatureSupported(feature))
|
||||||
|
theApp->getOPs().setFeatureBlocked();
|
||||||
|
|
||||||
return tesSUCCESS;
|
return tesSUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,17 @@
|
|||||||
|
|
||||||
SETUP_LOG (FeatureTable)
|
SETUP_LOG (FeatureTable)
|
||||||
|
|
||||||
|
FeatureState* testFeature = NULL;
|
||||||
|
|
||||||
void FeatureTable::addInitialFeatures()
|
void FeatureTable::addInitialFeatures()
|
||||||
{
|
{
|
||||||
// For each feature this version supports, call enableFeature.
|
// For each feature this version supports, construct the FeatureState object by calling
|
||||||
// Permanent vetos can also be added here.
|
// getCreateFeature. Set any vetoes or defaults. A pointer to the FeatureState can be stashed
|
||||||
|
|
||||||
|
testFeature = addKnownFeature("1234", "testFeature", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
FeatureTable::FeatureState* FeatureTable::getCreateFeature(const uint256& featureHash, bool create)
|
FeatureState* FeatureTable::getCreateFeature(const uint256& featureHash, bool create)
|
||||||
{ // call with the mutex held
|
{ // call with the mutex held
|
||||||
featureMap_t::iterator it = mFeatureMap.find(featureHash);
|
featureMap_t::iterator it = mFeatureMap.find(featureHash);
|
||||||
if (it == mFeatureMap.end())
|
if (it == mFeatureMap.end())
|
||||||
@@ -36,6 +40,39 @@ FeatureTable::FeatureState* FeatureTable::getCreateFeature(const uint256& featur
|
|||||||
return &(it->second);
|
return &(it->second);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint256 FeatureTable::getFeature(const std::string& name)
|
||||||
|
{
|
||||||
|
if (!name.empty())
|
||||||
|
{
|
||||||
|
BOOST_FOREACH(featureMap_t::value_type& it, mFeatureMap)
|
||||||
|
{
|
||||||
|
if (name == it.second.mFriendlyName)
|
||||||
|
return it.first;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return uint256();
|
||||||
|
}
|
||||||
|
|
||||||
|
FeatureState* FeatureTable::addKnownFeature(const char *featureID, const char *friendlyName, bool veto)
|
||||||
|
{
|
||||||
|
uint256 hash;
|
||||||
|
hash.SetHex(featureID);
|
||||||
|
if (hash.isZero())
|
||||||
|
{
|
||||||
|
assert(false);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
FeatureState* f = getCreateFeature(hash, true);
|
||||||
|
|
||||||
|
if (friendlyName != NULL)
|
||||||
|
f->setFriendlyName(friendlyName);
|
||||||
|
|
||||||
|
f->mVetoed = veto;
|
||||||
|
f->mSupported = true;
|
||||||
|
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
bool FeatureTable::vetoFeature(const uint256& feature)
|
bool FeatureTable::vetoFeature(const uint256& feature)
|
||||||
{
|
{
|
||||||
boost::mutex::scoped_lock sl(mMutex);
|
boost::mutex::scoped_lock sl(mMutex);
|
||||||
@@ -83,6 +120,13 @@ bool FeatureTable::isFeatureEnabled(const uint256& feature)
|
|||||||
return s && s->mEnabled;
|
return s && s->mEnabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool FeatureTable::isFeatureSupported(const uint256& feature)
|
||||||
|
{
|
||||||
|
boost::mutex::scoped_lock sl(mMutex);
|
||||||
|
FeatureState *s = getCreateFeature(feature, false);
|
||||||
|
return s && s->mSupported;
|
||||||
|
}
|
||||||
|
|
||||||
FeatureTable::featureList_t FeatureTable::getVetoedFeatures()
|
FeatureTable::featureList_t FeatureTable::getVetoedFeatures()
|
||||||
{
|
{
|
||||||
featureList_t ret;
|
featureList_t ret;
|
||||||
@@ -193,7 +237,22 @@ void FeatureTable::reportValidations(const FeatureSet& set)
|
|||||||
|
|
||||||
if (!changedFeatures.empty())
|
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 +305,12 @@ void FeatureTable::doVoting(Ledger::ref lastClosedLedger, SHAMap::ref initialPos
|
|||||||
|
|
||||||
BOOST_FOREACH(const uint256& uFeature, lFeatures)
|
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);
|
SerializedTransaction trans(ttFEATURE);
|
||||||
trans.setFieldAccount(sfAccount, uint160());
|
trans.setFieldAccount(sfAccount, uint160());
|
||||||
trans.setFieldH256(sfFeature, uFeature);
|
trans.setFieldH256(sfFeature, uFeature);
|
||||||
uint256 txID = trans.getTransactionID();
|
uint256 txID = trans.getTransactionID();
|
||||||
WriteLog (lsWARNING, FeatureTable) << "Vote: " << txID;
|
WriteLog (lsWARNING, FeatureTable) << "Vote ID: " << txID;
|
||||||
|
|
||||||
Serializer s;
|
Serializer s;
|
||||||
trans.add(s, true);
|
trans.add(s, true);
|
||||||
@@ -271,46 +330,60 @@ Json::Value FeatureTable::getJson(int)
|
|||||||
boost::mutex::scoped_lock sl(mMutex);
|
boost::mutex::scoped_lock sl(mMutex);
|
||||||
BOOST_FOREACH(const featureIt_t& it, mFeatureMap)
|
BOOST_FOREACH(const featureIt_t& it, mFeatureMap)
|
||||||
{
|
{
|
||||||
Json::Value v(Json::objectValue);
|
setJson(ret[it.first.GetHex()] = Json::objectValue, it.second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
v["supported"] = it.second.mSupported;
|
void FeatureTable::setJson(Json::Value& v, const FeatureState& fs)
|
||||||
|
{
|
||||||
|
if (!fs.mFriendlyName.empty())
|
||||||
|
v["name"] = fs.mFriendlyName;
|
||||||
|
|
||||||
if (it.second.mEnabled)
|
v["supported"] = fs.mSupported;
|
||||||
v["enabled"] = true;
|
v["vetoed"] = fs.mVetoed;
|
||||||
|
|
||||||
|
if (fs.mEnabled)
|
||||||
|
v["enabled"] = true;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
v["enabled"] = false;
|
||||||
|
if (mLastReport != 0)
|
||||||
|
{
|
||||||
|
if (fs.mLastMajority == 0)
|
||||||
|
{
|
||||||
|
v["majority"] = false;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
v["enabled"] = false;
|
if (fs.mFirstMajority != 0)
|
||||||
if (mLastReport != 0)
|
|
||||||
{
|
{
|
||||||
if (it.second.mLastMajority == 0)
|
if (fs.mFirstMajority == mFirstReport)
|
||||||
v["majority"] = false;
|
v["majority_start"] = "start";
|
||||||
else
|
else
|
||||||
{
|
v["majority_start"] = fs.mFirstMajority;
|
||||||
if (it.second.mFirstMajority != 0)
|
}
|
||||||
{
|
if (fs.mLastMajority != 0)
|
||||||
if (it.second.mFirstMajority == mFirstReport)
|
{
|
||||||
v["majority_start"] = "start";
|
if (fs.mLastMajority == mLastReport)
|
||||||
else
|
v["majority_until"] = "now";
|
||||||
v["majority_start"] = it.second.mFirstMajority;
|
else
|
||||||
}
|
v["majority_until"] = fs.mLastMajority;
|
||||||
if (it.second.mLastMajority != 0)
|
|
||||||
{
|
|
||||||
if (it.second.mLastMajority == mLastReport)
|
|
||||||
v["majority_until"] = "now";
|
|
||||||
else
|
|
||||||
v["majority_until"] = it.second.mLastMajority;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (it.second.mVetoed)
|
|
||||||
v["veto"] = true;
|
|
||||||
|
|
||||||
ret[it.first.GetHex()] = v;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (fs.mVetoed)
|
||||||
|
v["veto"] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Json::Value FeatureTable::getJson(const uint256& feature)
|
||||||
|
{
|
||||||
|
Json::Value ret = Json::objectValue;
|
||||||
|
boost::mutex::scoped_lock sl(mMutex);
|
||||||
|
setJson(ret[feature.GetHex()] = Json::objectValue, *getCreateFeature(feature, true));
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -350,6 +423,7 @@ public:
|
|||||||
typedef typename std::map<INT, int>::value_type mapVType;
|
typedef typename std::map<INT, int>::value_type mapVType;
|
||||||
BOOST_FOREACH(const mapVType& value, mVoteMap)
|
BOOST_FOREACH(const mapVType& value, mVoteMap)
|
||||||
{ // Take most voted value between current and target, inclusive
|
{ // 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)) &&
|
if ((value.first <= std::max(mTarget, mCurrent)) &&
|
||||||
(value.first >= std::min(mTarget, mCurrent)) &&
|
(value.first >= std::min(mTarget, mCurrent)) &&
|
||||||
(value.second > weight))
|
(value.second > weight))
|
||||||
|
|||||||
@@ -18,23 +18,38 @@ public:
|
|||||||
void addVote(const uint256& feature) { ++mVotes[feature]; }
|
void addVote(const uint256& feature) { ++mVotes[feature]; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class FeatureState
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
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)
|
||||||
|
|
||||||
|
std::string mFriendlyName;
|
||||||
|
|
||||||
|
FeatureState()
|
||||||
|
: mVetoed(false), mEnabled(false), mSupported(false), mDefault(false),
|
||||||
|
mFirstMajority(0), mLastMajority(0) { ; }
|
||||||
|
|
||||||
|
void setVeto() { mVetoed = true; }
|
||||||
|
void setDefault() { mDefault = true; }
|
||||||
|
bool isDefault() { return mDefault; }
|
||||||
|
bool isSupported() { return mSupported; }
|
||||||
|
bool isVetoed() { return mVetoed; }
|
||||||
|
bool isEnabled() { return mEnabled; }
|
||||||
|
const std::string& getFiendlyName() { return mFriendlyName; }
|
||||||
|
void setFriendlyName(const std::string& n) { mFriendlyName = n; }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
class FeatureTable
|
class FeatureTable
|
||||||
{
|
{
|
||||||
protected:
|
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<uint256, FeatureState> featureMap_t;
|
typedef boost::unordered_map<uint256, FeatureState> featureMap_t;
|
||||||
typedef std::pair<const uint256, FeatureState> featureIt_t;
|
typedef std::pair<const uint256, FeatureState> featureIt_t;
|
||||||
typedef boost::unordered_set<uint256> featureList_t;
|
typedef boost::unordered_set<uint256> featureList_t;
|
||||||
@@ -48,15 +63,19 @@ protected:
|
|||||||
|
|
||||||
FeatureState* getCreateFeature(const uint256& feature, bool create);
|
FeatureState* getCreateFeature(const uint256& feature, bool create);
|
||||||
bool shouldEnable (uint32 closeTime, const FeatureState& fs);
|
bool shouldEnable (uint32 closeTime, const FeatureState& fs);
|
||||||
|
void setJson(Json::Value& v, const FeatureState&);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
FeatureTable(uint32 majorityTime, int majorityFraction)
|
FeatureTable(uint32 majorityTime, int majorityFraction)
|
||||||
: mMajorityTime(majorityTime), mMajorityFraction(majorityFraction), mFirstReport(0), mLastReport(0)
|
: mMajorityTime(majorityTime), mMajorityFraction(majorityFraction), mFirstReport(0), mLastReport(0)
|
||||||
{ addInitialFeatures(); }
|
{ ; }
|
||||||
|
|
||||||
void addInitialFeatures();
|
void addInitialFeatures();
|
||||||
|
|
||||||
|
FeatureState* addKnownFeature(const char *featureID, const char *friendlyName, bool veto);
|
||||||
|
uint256 getFeature(const std::string& name);
|
||||||
|
|
||||||
bool vetoFeature(const uint256& feature);
|
bool vetoFeature(const uint256& feature);
|
||||||
bool unVetoFeature(const uint256& feature);
|
bool unVetoFeature(const uint256& feature);
|
||||||
|
|
||||||
@@ -64,6 +83,7 @@ public:
|
|||||||
bool disableFeature(const uint256& feature);
|
bool disableFeature(const uint256& feature);
|
||||||
|
|
||||||
bool isFeatureEnabled(const uint256& feature);
|
bool isFeatureEnabled(const uint256& feature);
|
||||||
|
bool isFeatureSupported(const uint256& feature);
|
||||||
|
|
||||||
void setEnabledFeatures(const std::vector<uint256>& features);
|
void setEnabledFeatures(const std::vector<uint256>& features);
|
||||||
void setSupportedFeatures(const std::vector<uint256>& features);
|
void setSupportedFeatures(const std::vector<uint256>& features);
|
||||||
@@ -76,6 +96,7 @@ public:
|
|||||||
void reportValidations(const FeatureSet&);
|
void reportValidations(const FeatureSet&);
|
||||||
|
|
||||||
Json::Value getJson(int);
|
Json::Value getJson(int);
|
||||||
|
Json::Value getJson(const uint256&);
|
||||||
|
|
||||||
void doValidation(Ledger::ref lastClosedLedger, STObject& baseValidation);
|
void doValidation(Ledger::ref lastClosedLedger, STObject& baseValidation);
|
||||||
void doVoting(Ledger::ref lastClosedLedger, SHAMap::ref initialPosition);
|
void doVoting(Ledger::ref lastClosedLedger, SHAMap::ref initialPosition);
|
||||||
|
|||||||
@@ -1327,6 +1327,15 @@ std::vector< std::pair<uint32, uint256> > Ledger::getLedgerHashes()
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<uint256> Ledger::getLedgerFeatures()
|
||||||
|
{
|
||||||
|
std::vector<uint256> usFeatures;
|
||||||
|
SLE::pointer sleFeatures = getSLEi(getLedgerFeatureIndex());
|
||||||
|
if (sleFeatures)
|
||||||
|
usFeatures = sleFeatures->getFieldV256(sfFeatures).peekValue();
|
||||||
|
return usFeatures;
|
||||||
|
}
|
||||||
|
|
||||||
// XRP to XRP not allowed.
|
// XRP to XRP not allowed.
|
||||||
// Currencies must have appropriate issuer.
|
// Currencies must have appropriate issuer.
|
||||||
// Currencies or accounts must differ.
|
// Currencies or accounts must differ.
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
#include <list>
|
#include <list>
|
||||||
|
|
||||||
#include <boost/shared_ptr.hpp>
|
#include <boost/shared_ptr.hpp>
|
||||||
|
#include <boost/unordered_set.hpp>
|
||||||
#include <boost/enable_shared_from_this.hpp>
|
#include <boost/enable_shared_from_this.hpp>
|
||||||
#include <boost/date_time/posix_time/posix_time.hpp>
|
#include <boost/date_time/posix_time/posix_time.hpp>
|
||||||
|
|
||||||
@@ -219,6 +220,7 @@ public:
|
|||||||
|
|
||||||
static uint256 getLedgerFeatureIndex();
|
static uint256 getLedgerFeatureIndex();
|
||||||
static uint256 getLedgerFeeIndex();
|
static uint256 getLedgerFeeIndex();
|
||||||
|
std::vector<uint256> getLedgerFeatures();
|
||||||
|
|
||||||
std::vector<uint256> getNeededTransactionHashes(int max, SHAMapSyncFilter* filter);
|
std::vector<uint256> getNeededTransactionHashes(int max, SHAMapSyncFilter* filter);
|
||||||
std::vector<uint256> getNeededAccountStateHashes(int max, SHAMapSyncFilter* filter);
|
std::vector<uint256> getNeededAccountStateHashes(int max, SHAMapSyncFilter* filter);
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ void InfoSub::onSendEmpty()
|
|||||||
|
|
||||||
NetworkOPs::NetworkOPs(boost::asio::io_service& io_service, LedgerMaster* pLedgerMaster) :
|
NetworkOPs::NetworkOPs(boost::asio::io_service& io_service, LedgerMaster* pLedgerMaster) :
|
||||||
mMode(omDISCONNECTED), mNeedNetworkLedger(false), mProposing(false), mValidating(false),
|
mMode(omDISCONNECTED), mNeedNetworkLedger(false), mProposing(false), mValidating(false),
|
||||||
|
mFeatureBlocked(false),
|
||||||
mNetTimer(io_service), mLedgerMaster(pLedgerMaster), mCloseTimeOffset(0), mLastCloseProposers(0),
|
mNetTimer(io_service), mLedgerMaster(pLedgerMaster), mCloseTimeOffset(0), mLastCloseProposers(0),
|
||||||
mLastCloseConvergeTime(1000 * LEDGER_IDLE_INTERVAL), mLastCloseTime(0), mLastValidationTime(0),
|
mLastCloseConvergeTime(1000 * LEDGER_IDLE_INTERVAL), mLastCloseTime(0), mLastValidationTime(0),
|
||||||
mFetchPack("FetchPack", 2048, 20), mLastFetchPack(0), mFetchSeq(static_cast<uint32>(-1)),
|
mFetchPack("FetchPack", 2048, 20), mLastFetchPack(0), mFetchSeq(static_cast<uint32>(-1)),
|
||||||
@@ -553,6 +554,12 @@ Json::Value NetworkOPs::getOwnerInfo(Ledger::pointer lpLedger, const RippleAddre
|
|||||||
// Other
|
// Other
|
||||||
//
|
//
|
||||||
|
|
||||||
|
void NetworkOPs::setFeatureBlocked()
|
||||||
|
{
|
||||||
|
mFeatureBlocked = true;
|
||||||
|
setMode(omTRACKING);
|
||||||
|
}
|
||||||
|
|
||||||
void NetworkOPs::setStateTimer()
|
void NetworkOPs::setStateTimer()
|
||||||
{
|
{
|
||||||
mNetTimer.expires_from_now(boost::posix_time::milliseconds(LEDGER_GRANULARITY));
|
mNetTimer.expires_from_now(boost::posix_time::milliseconds(LEDGER_GRANULARITY));
|
||||||
@@ -1047,6 +1054,9 @@ void NetworkOPs::setMode(OperatingMode om)
|
|||||||
om = omCONNECTED;
|
om = omCONNECTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((om > omTRACKING) && mFeatureBlocked)
|
||||||
|
om = omTRACKING;
|
||||||
|
|
||||||
if (mMode == om)
|
if (mMode == om)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -1265,6 +1275,8 @@ Json::Value NetworkOPs::getServerInfo(bool human, bool admin)
|
|||||||
|
|
||||||
info["complete_ledgers"] = theApp->getLedgerMaster().getCompleteLedgers();
|
info["complete_ledgers"] = theApp->getLedgerMaster().getCompleteLedgers();
|
||||||
|
|
||||||
|
if (mFeatureBlocked)
|
||||||
|
info["feature_blocked"] = true;
|
||||||
|
|
||||||
size_t fp = mFetchPack.getCacheSize();
|
size_t fp = mFetchPack.getCacheSize();
|
||||||
if (fp != 0)
|
if (fp != 0)
|
||||||
|
|||||||
@@ -115,6 +115,7 @@ protected:
|
|||||||
OperatingMode mMode;
|
OperatingMode mMode;
|
||||||
bool mNeedNetworkLedger;
|
bool mNeedNetworkLedger;
|
||||||
bool mProposing, mValidating;
|
bool mProposing, mValidating;
|
||||||
|
bool mFeatureBlocked;
|
||||||
boost::posix_time::ptime mConnectTime;
|
boost::posix_time::ptime mConnectTime;
|
||||||
boost::asio::deadline_timer mNetTimer;
|
boost::asio::deadline_timer mNetTimer;
|
||||||
boost::shared_ptr<LedgerConsensus> mConsensus;
|
boost::shared_ptr<LedgerConsensus> mConsensus;
|
||||||
@@ -309,6 +310,8 @@ public:
|
|||||||
void setProposing(bool p, bool v) { mProposing = p; mValidating = v; }
|
void setProposing(bool p, bool v) { mProposing = p; mValidating = v; }
|
||||||
bool isProposing() { return mProposing; }
|
bool isProposing() { return mProposing; }
|
||||||
bool isValidating() { return mValidating; }
|
bool isValidating() { return mValidating; }
|
||||||
|
bool isFeatureBlocked() { return mFeatureBlocked; }
|
||||||
|
void setFeatureBlocked();
|
||||||
void consensusViewChange();
|
void consensusViewChange();
|
||||||
int getPreviousProposers() { return mLastCloseProposers; }
|
int getPreviousProposers() { return mLastCloseProposers; }
|
||||||
int getPreviousConvergeTime() { return mLastCloseConvergeTime; }
|
int getPreviousConvergeTime() { return mLastCloseConvergeTime; }
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ Json::Value rpcError(int iError, Json::Value jvResult)
|
|||||||
{ rpcACT_MALFORMED, "actMalformed", "Account malformed." },
|
{ rpcACT_MALFORMED, "actMalformed", "Account malformed." },
|
||||||
{ rpcACT_NOT_FOUND, "actNotFound", "Account not found." },
|
{ rpcACT_NOT_FOUND, "actNotFound", "Account not found." },
|
||||||
{ rpcBAD_BLOB, "badBlob", "Blob must be a non-empty hex string." },
|
{ rpcBAD_BLOB, "badBlob", "Blob must be a non-empty hex string." },
|
||||||
|
{ rpcBAD_FEATURE, "badFeature", "Feature unknown or invalid." },
|
||||||
{ rpcBAD_ISSUER, "badIssuer", "Issuer account malformed." },
|
{ rpcBAD_ISSUER, "badIssuer", "Issuer account malformed." },
|
||||||
{ rpcBAD_MARKET, "badMarket", "No such market." },
|
{ rpcBAD_MARKET, "badMarket", "No such market." },
|
||||||
{ rpcBAD_SECRET, "badSecret", "Secret does not match account." },
|
{ rpcBAD_SECRET, "badSecret", "Secret does not match account." },
|
||||||
|
|||||||
@@ -47,6 +47,7 @@ enum {
|
|||||||
rpcACT_MALFORMED,
|
rpcACT_MALFORMED,
|
||||||
rpcQUALITY_MALFORMED,
|
rpcQUALITY_MALFORMED,
|
||||||
rpcBAD_BLOB,
|
rpcBAD_BLOB,
|
||||||
|
rpcBAD_FEATURE,
|
||||||
rpcBAD_ISSUER,
|
rpcBAD_ISSUER,
|
||||||
rpcBAD_MARKET,
|
rpcBAD_MARKET,
|
||||||
rpcBAD_SECRET,
|
rpcBAD_SECRET,
|
||||||
|
|||||||
@@ -2255,6 +2255,30 @@ static void textTime(std::string& text, int& seconds, const char *unitName, int
|
|||||||
text += "s";
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint256 uFeature = theApp->getFeatureTable().getFeature(jvRequest["feature"].asString());
|
||||||
|
if (uFeature.isZero())
|
||||||
|
{
|
||||||
|
uFeature.SetHex(jvRequest["feature"].asString());
|
||||||
|
if (uFeature.isZero())
|
||||||
|
return rpcError(rpcBAD_FEATURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!jvRequest.isMember("vote"))
|
||||||
|
return theApp->getFeatureTable().getJson(uFeature);
|
||||||
|
|
||||||
|
// WRITEME
|
||||||
|
return rpcError(rpcNOT_SUPPORTED);
|
||||||
|
}
|
||||||
|
|
||||||
// {
|
// {
|
||||||
// min_count: <number> // optional, defaults to 10
|
// min_count: <number> // optional, defaults to 10
|
||||||
// }
|
// }
|
||||||
@@ -3461,6 +3485,7 @@ Json::Value RPCHandler::doCommand(const Json::Value& jvRequest, int iRole, int &
|
|||||||
{ "consensus_info", &RPCHandler::doConsensusInfo, true, optNone },
|
{ "consensus_info", &RPCHandler::doConsensusInfo, true, optNone },
|
||||||
{ "get_counts", &RPCHandler::doGetCounts, true, optNone },
|
{ "get_counts", &RPCHandler::doGetCounts, true, optNone },
|
||||||
{ "internal", &RPCHandler::doInternal, true, optNone },
|
{ "internal", &RPCHandler::doInternal, true, optNone },
|
||||||
|
{ "feature", &RPCHandler::doFeature, true, optNone },
|
||||||
{ "ledger", &RPCHandler::doLedger, false, optNetwork },
|
{ "ledger", &RPCHandler::doLedger, false, optNetwork },
|
||||||
{ "ledger_accept", &RPCHandler::doLedgerAccept, true, optCurrent },
|
{ "ledger_accept", &RPCHandler::doLedgerAccept, true, optCurrent },
|
||||||
{ "ledger_closed", &RPCHandler::doLedgerClosed, false, optClosed },
|
{ "ledger_closed", &RPCHandler::doLedgerClosed, false, optClosed },
|
||||||
|
|||||||
@@ -57,6 +57,7 @@ class RPCHandler
|
|||||||
Json::Value doDataFetch(Json::Value params, int& cost, ScopedLock& mlh);
|
Json::Value doDataFetch(Json::Value params, int& cost, ScopedLock& mlh);
|
||||||
Json::Value doDataStore(Json::Value params, int& cost, ScopedLock& mlh);
|
Json::Value doDataStore(Json::Value params, int& cost, ScopedLock& mlh);
|
||||||
#endif
|
#endif
|
||||||
|
Json::Value doFeature(Json::Value params, int& cost, ScopedLock& mlh);
|
||||||
Json::Value doGetCounts(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 doInternal(Json::Value params, int& cost, ScopedLock& mlh);
|
||||||
Json::Value doLedger(Json::Value params, int& cost, ScopedLock& mlh);
|
Json::Value doLedger(Json::Value params, int& cost, ScopedLock& mlh);
|
||||||
|
|||||||
Reference in New Issue
Block a user